text overlay positions preset
This commit is contained in:
+23
-4
@@ -35,6 +35,7 @@ type appArgs struct {
|
|||||||
textOverlay string
|
textOverlay string
|
||||||
overlayX int
|
overlayX int
|
||||||
overlayY int
|
overlayY int
|
||||||
|
overlayPos string
|
||||||
|
|
||||||
videoWidth uint
|
videoWidth uint
|
||||||
videoHeight uint
|
videoHeight uint
|
||||||
@@ -277,9 +278,26 @@ func flagSetAddFlags(fs *pflag.FlagSet, args *appArgs) {
|
|||||||
fs.StringVarP(&args.pattern, "pattern", "p", "bars", "Video pattern type")
|
fs.StringVarP(&args.pattern, "pattern", "p", "bars", "Video pattern type")
|
||||||
fs.BoolVar(&args.listPatterns, "list-patterns", false, "List video available video patterns and exit")
|
fs.BoolVar(&args.listPatterns, "list-patterns", false, "List video available video patterns and exit")
|
||||||
|
|
||||||
fs.StringVarP(&args.textOverlay, "text", "t", "", "Text overlay above video pattern")
|
fs.StringVarP(&args.textOverlay, "text", "t", "", "Text overlay above video pattern. Ignored if text-pos set")
|
||||||
fs.IntVar(&args.overlayX, "text-x", 0, "Text overlay X position in px")
|
fs.IntVar(&args.overlayX, "text-x", 0, "Text overlay X position in px. Ignored if text-pos set")
|
||||||
fs.IntVar(&args.overlayY, "text-y", 0, "Text overlay Y position in px")
|
fs.IntVar(
|
||||||
|
&args.overlayY,
|
||||||
|
"text-y",
|
||||||
|
0,
|
||||||
|
"Text overlay Y position in px")
|
||||||
|
fs.StringVar(
|
||||||
|
&args.overlayPos,
|
||||||
|
"text-pos",
|
||||||
|
"",
|
||||||
|
"Text overlay position with pre-defined values:\n"+
|
||||||
|
"tl - top-left corner\n"+
|
||||||
|
"tc - top-center\n"+
|
||||||
|
"tr - top-right corner\n"+
|
||||||
|
"cc - center of the frame\n"+
|
||||||
|
"bl - bottom-left corner\n"+
|
||||||
|
"bc - bottom-center\n"+
|
||||||
|
"br - bottom-right corner",
|
||||||
|
)
|
||||||
|
|
||||||
fs.UintVar(&args.videoWidth, "width", 1920, "Video pattern width")
|
fs.UintVar(&args.videoWidth, "width", 1920, "Video pattern width")
|
||||||
fs.UintVar(&args.videoHeight, "height", 1080, "Video pattern height")
|
fs.UintVar(&args.videoHeight, "height", 1080, "Video pattern height")
|
||||||
@@ -376,7 +394,7 @@ func main() {
|
|||||||
args.overlayX > int(vi.width) ||
|
args.overlayX > int(vi.width) ||
|
||||||
args.overlayY < 0 ||
|
args.overlayY < 0 ||
|
||||||
args.overlayY > int(vi.height) {
|
args.overlayY > int(vi.height) {
|
||||||
log.Fatalf("Overlay X/Y pos can't be negative or greater, than video width/height")
|
log.Fatalf("overlay X/Y pos can't be negative or greater, than video width/height")
|
||||||
}
|
}
|
||||||
overlay, err = generator.NewTextOverlay(
|
overlay, err = generator.NewTextOverlay(
|
||||||
args.textOverlay,
|
args.textOverlay,
|
||||||
@@ -384,6 +402,7 @@ func main() {
|
|||||||
int(vi.height),
|
int(vi.height),
|
||||||
args.overlayX,
|
args.overlayX,
|
||||||
args.overlayY,
|
args.overlayY,
|
||||||
|
args.overlayPos,
|
||||||
face,
|
face,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"os"
|
"os"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"golang.org/x/image/font"
|
"golang.org/x/image/font"
|
||||||
"golang.org/x/image/font/opentype"
|
"golang.org/x/image/font/opentype"
|
||||||
@@ -22,6 +23,8 @@ type TextOverlay struct {
|
|||||||
blocks []byte // pre-packed v210 tile: h rows x (w/6) blocks x 16 bytes
|
blocks []byte // pre-packed v210 tile: h rows x (w/6) blocks x 16 bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var TextPosAvailable []string = []string{"tl", "tc", "tr", "cc", "bl", "bc", "br"}
|
||||||
|
|
||||||
// LoadFace parses a TTF/OTF file and builds a render-ready face at the given
|
// LoadFace parses a TTF/OTF file and builds a render-ready face at the given
|
||||||
// pixel size (DPI 72, full hinting for crisp video text). Call once and
|
// pixel size (DPI 72, full hinting for crisp video text). Call once and
|
||||||
// reuse for every overlay.
|
// reuse for every overlay.
|
||||||
@@ -48,7 +51,7 @@ func LoadFace(path string, size float64) (font.Face, error) {
|
|||||||
// NewTextOverlay rasterizes text (white, anti-aliased) onto a black backing box.
|
// NewTextOverlay rasterizes text (white, anti-aliased) onto a black backing box.
|
||||||
// Box width and x are multiples of 6 so the box
|
// Box width and x are multiples of 6 so the box
|
||||||
// covers whole v210 blocks and the per-frame copy is word-aligned.
|
// covers whole v210 blocks and the per-frame copy is word-aligned.
|
||||||
func NewTextOverlay(text string, frameW, frameH, posX, posY int, face font.Face) (*TextOverlay, error) {
|
func NewTextOverlay(text string, frameW, frameH, posX, posY int, textPos string, face font.Face) (*TextOverlay, error) {
|
||||||
if text == "" {
|
if text == "" {
|
||||||
return nil, fmt.Errorf("text: empty string")
|
return nil, fmt.Errorf("text: empty string")
|
||||||
}
|
}
|
||||||
@@ -89,8 +92,34 @@ func NewTextOverlay(text string, frameW, frameH, posX, posY int, face font.Face)
|
|||||||
return nil, fmt.Errorf("text: box %dpx does not fit frame height %dpx", topMargin+h, frameH)
|
return nil, fmt.Errorf("text: box %dpx does not fit frame height %dpx", topMargin+h, frameH)
|
||||||
}
|
}
|
||||||
|
|
||||||
// posX = ((frameW - w) / 2 / 6) * 6
|
if textPos != "" {
|
||||||
// posY = topMargin
|
if !slices.Contains(TextPosAvailable, textPos) {
|
||||||
|
return nil, fmt.Errorf("text: unknown text position preset '%s'", textPos)
|
||||||
|
}
|
||||||
|
switch textPos {
|
||||||
|
case "tl":
|
||||||
|
posX = 0
|
||||||
|
posY = 0
|
||||||
|
case "tc":
|
||||||
|
posX = ((frameW - w) / 2 / 6) * 6
|
||||||
|
posY = 0
|
||||||
|
case "tr":
|
||||||
|
posX = frameW - w
|
||||||
|
posY = 0
|
||||||
|
case "cc":
|
||||||
|
posX = ((frameW - w) / 2 / 6) * 6
|
||||||
|
posY = (frameH - h) / 2
|
||||||
|
case "bl":
|
||||||
|
posX = 0
|
||||||
|
posY = frameH - h
|
||||||
|
case "bc":
|
||||||
|
posX = ((frameW - w) / 2 / 6) * 6
|
||||||
|
posY = frameH - h
|
||||||
|
case "br":
|
||||||
|
posX = frameW - w
|
||||||
|
posY = frameH - h
|
||||||
|
}
|
||||||
|
}
|
||||||
o := &TextOverlay{
|
o := &TextOverlay{
|
||||||
frameW: frameW,
|
frameW: frameW,
|
||||||
x: posX,
|
x: posX,
|
||||||
|
|||||||
Reference in New Issue
Block a user