text overlay positions preset
This commit is contained in:
+23
-4
@@ -35,6 +35,7 @@ type appArgs struct {
|
||||
textOverlay string
|
||||
overlayX int
|
||||
overlayY int
|
||||
overlayPos string
|
||||
|
||||
videoWidth 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.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.IntVar(&args.overlayX, "text-x", 0, "Text overlay X position in px")
|
||||
fs.IntVar(&args.overlayY, "text-y", 0, "Text overlay Y position in px")
|
||||
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. Ignored if text-pos set")
|
||||
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.videoHeight, "height", 1080, "Video pattern height")
|
||||
@@ -376,7 +394,7 @@ func main() {
|
||||
args.overlayX > int(vi.width) ||
|
||||
args.overlayY < 0 ||
|
||||
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(
|
||||
args.textOverlay,
|
||||
@@ -384,6 +402,7 @@ func main() {
|
||||
int(vi.height),
|
||||
args.overlayX,
|
||||
args.overlayY,
|
||||
args.overlayPos,
|
||||
face,
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"image"
|
||||
"os"
|
||||
"slices"
|
||||
|
||||
"golang.org/x/image/font"
|
||||
"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
|
||||
}
|
||||
|
||||
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
|
||||
// pixel size (DPI 72, full hinting for crisp video text). Call once and
|
||||
// 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.
|
||||
// Box width and x are multiples of 6 so the box
|
||||
// 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 == "" {
|
||||
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)
|
||||
}
|
||||
|
||||
// posX = ((frameW - w) / 2 / 6) * 6
|
||||
// posY = topMargin
|
||||
if textPos != "" {
|
||||
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{
|
||||
frameW: frameW,
|
||||
x: posX,
|
||||
|
||||
Reference in New Issue
Block a user