Clamp menu logo scale and add preview
This commit is contained in:
parent
c3bd5a0baa
commit
ea7cfbbf6a
|
|
@ -298,7 +298,7 @@ func buildMenuBackground(ctx context.Context, outputPath, title string, buttons
|
||||||
logoPath := resolveMenuLogoPath(logo)
|
logoPath := resolveMenuLogoPath(logo)
|
||||||
if logoPath != "" {
|
if logoPath != "" {
|
||||||
posExpr := resolveMenuLogoPosition(logo, width, height)
|
posExpr := resolveMenuLogoPosition(logo, width, height)
|
||||||
scaleExpr := fmt.Sprintf("scale=iw*%.2f:ih*%.2f", resolveMenuLogoScale(logo), resolveMenuLogoScale(logo))
|
scaleExpr := resolveMenuLogoScaleExpr(logo, width, height)
|
||||||
args = append(args, "-i", logoPath)
|
args = append(args, "-i", logoPath)
|
||||||
filterExpr = fmt.Sprintf("[0:v]%s[bg];[1:v]%s[logo];[bg][logo]overlay=%s", filterChain, scaleExpr, posExpr)
|
filterExpr = fmt.Sprintf("[0:v]%s[bg];[1:v]%s[logo];[bg][logo]overlay=%s", filterChain, scaleExpr, posExpr)
|
||||||
}
|
}
|
||||||
|
|
@ -343,7 +343,7 @@ func buildDarkMenuBackground(ctx context.Context, outputPath, title string, butt
|
||||||
logoPath := resolveMenuLogoPath(logo)
|
logoPath := resolveMenuLogoPath(logo)
|
||||||
if logoPath != "" {
|
if logoPath != "" {
|
||||||
posExpr := resolveMenuLogoPosition(logo, width, height)
|
posExpr := resolveMenuLogoPosition(logo, width, height)
|
||||||
scaleExpr := fmt.Sprintf("scale=iw*%.2f:ih*%.2f", resolveMenuLogoScale(logo), resolveMenuLogoScale(logo))
|
scaleExpr := resolveMenuLogoScaleExpr(logo, width, height)
|
||||||
args = append(args, "-i", logoPath)
|
args = append(args, "-i", logoPath)
|
||||||
filterExpr = fmt.Sprintf("[0:v]%s[bg];[1:v]%s[logo];[bg][logo]overlay=%s", filterChain, scaleExpr, posExpr)
|
filterExpr = fmt.Sprintf("[0:v]%s[bg];[1:v]%s[logo];[bg][logo]overlay=%s", filterChain, scaleExpr, posExpr)
|
||||||
}
|
}
|
||||||
|
|
@ -381,7 +381,7 @@ func buildPosterMenuBackground(ctx context.Context, outputPath, title string, bu
|
||||||
logoPath := resolveMenuLogoPath(logo)
|
logoPath := resolveMenuLogoPath(logo)
|
||||||
if logoPath != "" {
|
if logoPath != "" {
|
||||||
posExpr := resolveMenuLogoPosition(logo, width, height)
|
posExpr := resolveMenuLogoPosition(logo, width, height)
|
||||||
scaleExpr := fmt.Sprintf("scale=iw*%.2f:ih*%.2f", resolveMenuLogoScale(logo), resolveMenuLogoScale(logo))
|
scaleExpr := resolveMenuLogoScaleExpr(logo, width, height)
|
||||||
args = append(args, "-i", logoPath)
|
args = append(args, "-i", logoPath)
|
||||||
filterExpr = fmt.Sprintf("[0:v]scale=%d:%d,%s[bg];[1:v]%s[logo];[bg][logo]overlay=%s", width, height, filterChain, scaleExpr, posExpr)
|
filterExpr = fmt.Sprintf("[0:v]scale=%d:%d,%s[bg];[1:v]%s[logo];[bg][logo]overlay=%s", width, height, filterChain, scaleExpr, posExpr)
|
||||||
}
|
}
|
||||||
|
|
@ -573,6 +573,13 @@ func resolveMenuLogoScale(logo menuLogoOptions) float64 {
|
||||||
return logo.Scale
|
return logo.Scale
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resolveMenuLogoScaleExpr(logo menuLogoOptions, width, height int) string {
|
||||||
|
scale := resolveMenuLogoScale(logo)
|
||||||
|
maxW := float64(width) * 0.25
|
||||||
|
maxH := float64(height) * 0.25
|
||||||
|
return fmt.Sprintf("scale=w='min(iw*%.2f,%.0f)':h='min(ih*%.2f,%.0f)':force_original_aspect_ratio=decrease", scale, maxW, scale, maxH)
|
||||||
|
}
|
||||||
|
|
||||||
func resolveMenuLogoPosition(logo menuLogoOptions, width, height int) string {
|
func resolveMenuLogoPosition(logo menuLogoOptions, width, height int) string {
|
||||||
margin := logo.Margin
|
margin := logo.Margin
|
||||||
if margin < 0 {
|
if margin < 0 {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
|
@ -1030,6 +1031,78 @@ func buildAuthorMenuTab(state *appState) fyne.CanvasObject {
|
||||||
|
|
||||||
logoLabel := widget.NewLabel(state.authorMenuLogoPath)
|
logoLabel := widget.NewLabel(state.authorMenuLogoPath)
|
||||||
logoLabel.Wrapping = fyne.TextWrapWord
|
logoLabel.Wrapping = fyne.TextWrapWord
|
||||||
|
logoPreview := canvas.NewImageFromFile("")
|
||||||
|
logoPreview.FillMode = canvas.ImageFillContain
|
||||||
|
logoPreview.SetMinSize(fyne.NewSize(220, 120))
|
||||||
|
logoPreviewLabel := widget.NewLabel("No logo selected")
|
||||||
|
logoPreviewLabel.Wrapping = fyne.TextWrapWord
|
||||||
|
logoPreviewSize := widget.NewLabel("")
|
||||||
|
logoPreviewSize.Wrapping = fyne.TextWrapWord
|
||||||
|
|
||||||
|
menuPreviewSize := func() (int, int) {
|
||||||
|
width := 720
|
||||||
|
height := 480
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(state.authorRegion)) {
|
||||||
|
case "PAL":
|
||||||
|
height = 576
|
||||||
|
}
|
||||||
|
return width, height
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLogoPreview := func() {
|
||||||
|
if !state.authorMenuLogoEnabled {
|
||||||
|
logoPreview.Hide()
|
||||||
|
logoPreviewLabel.SetText("Logo preview disabled")
|
||||||
|
logoPreviewSize.SetText("")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
path := state.authorMenuLogoPath
|
||||||
|
if strings.TrimSpace(path) == "" {
|
||||||
|
path = filepath.Join("assets", "logo", "VT_Logo.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := os.Stat(path); err != nil {
|
||||||
|
logoPreview.Hide()
|
||||||
|
logoPreviewLabel.SetText("Logo file not found")
|
||||||
|
logoPreviewSize.SetText("")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logoPreview.Show()
|
||||||
|
logoPreviewLabel.SetText(filepath.Base(path))
|
||||||
|
logoPreview.File = path
|
||||||
|
logoPreview.Refresh()
|
||||||
|
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
logoPreviewSize.SetText("")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
cfg, _, err := image.DecodeConfig(file)
|
||||||
|
if err != nil {
|
||||||
|
logoPreviewSize.SetText("")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
menuW, menuH := menuPreviewSize()
|
||||||
|
maxW := int(float64(menuW) * 0.25)
|
||||||
|
maxH := int(float64(menuH) * 0.25)
|
||||||
|
scale := state.authorMenuLogoScale
|
||||||
|
targetW := int(math.Round(float64(cfg.Width) * scale))
|
||||||
|
targetH := int(math.Round(float64(cfg.Height) * scale))
|
||||||
|
if targetW > maxW || targetH > maxH {
|
||||||
|
ratioW := float64(maxW) / float64(targetW)
|
||||||
|
ratioH := float64(maxH) / float64(targetH)
|
||||||
|
ratio := math.Min(ratioW, ratioH)
|
||||||
|
targetW = int(math.Round(float64(targetW) * ratio))
|
||||||
|
targetH = int(math.Round(float64(targetH) * ratio))
|
||||||
|
}
|
||||||
|
|
||||||
|
logoPreviewSize.SetText(fmt.Sprintf("Logo size: %dx%d (max %dx%d)", targetW, targetH, maxW, maxH))
|
||||||
|
}
|
||||||
logoPickButton := widget.NewButton("Select Logo", func() {
|
logoPickButton := widget.NewButton("Select Logo", func() {
|
||||||
dialog.ShowFileOpen(func(reader fyne.URIReadCloser, err error) {
|
dialog.ShowFileOpen(func(reader fyne.URIReadCloser, err error) {
|
||||||
if err != nil || reader == nil {
|
if err != nil || reader == nil {
|
||||||
|
|
@ -1038,6 +1111,7 @@ func buildAuthorMenuTab(state *appState) fyne.CanvasObject {
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
state.authorMenuLogoPath = reader.URI().Path()
|
state.authorMenuLogoPath = reader.URI().Path()
|
||||||
logoLabel.SetText(state.authorMenuLogoPath)
|
logoLabel.SetText(state.authorMenuLogoPath)
|
||||||
|
updateLogoPreview()
|
||||||
state.updateAuthorSummary()
|
state.updateAuthorSummary()
|
||||||
state.persistAuthorConfig()
|
state.persistAuthorConfig()
|
||||||
}, state.window)
|
}, state.window)
|
||||||
|
|
@ -1082,6 +1156,7 @@ func buildAuthorMenuTab(state *appState) fyne.CanvasObject {
|
||||||
logoScaleSelect := widget.NewSelect(scaleOptions, func(value string) {
|
logoScaleSelect := widget.NewSelect(scaleOptions, func(value string) {
|
||||||
if scale, ok := scaleValueByLabel[value]; ok {
|
if scale, ok := scaleValueByLabel[value]; ok {
|
||||||
state.authorMenuLogoScale = scale
|
state.authorMenuLogoScale = scale
|
||||||
|
updateLogoPreview()
|
||||||
state.persistAuthorConfig()
|
state.persistAuthorConfig()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -1148,7 +1223,11 @@ func buildAuthorMenuTab(state *appState) fyne.CanvasObject {
|
||||||
info := widget.NewLabel("DVD menus are generated using the VideoTools theme and IBM Plex Mono. Menu settings apply only to disc authoring.")
|
info := widget.NewLabel("DVD menus are generated using the VideoTools theme and IBM Plex Mono. Menu settings apply only to disc authoring.")
|
||||||
info.Wrapping = fyne.TextWrapWord
|
info.Wrapping = fyne.TextWrapWord
|
||||||
|
|
||||||
previewBox := buildMenuBox("Preview", widget.NewLabel("Menu preview is generated during authoring."))
|
previewBox := buildMenuBox("Logo Preview", container.NewVBox(
|
||||||
|
logoPreviewLabel,
|
||||||
|
logoPreview,
|
||||||
|
logoPreviewSize,
|
||||||
|
))
|
||||||
|
|
||||||
menuCore := buildMenuBox("Menu Core", container.NewVBox(
|
menuCore := buildMenuBox("Menu Core", container.NewVBox(
|
||||||
createMenuCheck,
|
createMenuCheck,
|
||||||
|
|
@ -1233,11 +1312,13 @@ func buildAuthorMenuTab(state *appState) fyne.CanvasObject {
|
||||||
|
|
||||||
logoEnableCheck.OnChanged = func(checked bool) {
|
logoEnableCheck.OnChanged = func(checked bool) {
|
||||||
state.authorMenuLogoEnabled = checked
|
state.authorMenuLogoEnabled = checked
|
||||||
|
updateLogoPreview()
|
||||||
updateMenuControls(state.authorCreateMenu)
|
updateMenuControls(state.authorCreateMenu)
|
||||||
state.updateAuthorSummary()
|
state.updateAuthorSummary()
|
||||||
state.persistAuthorConfig()
|
state.persistAuthorConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateLogoPreview()
|
||||||
updateMenuControls(state.authorCreateMenu)
|
updateMenuControls(state.authorCreateMenu)
|
||||||
|
|
||||||
return container.NewPadded(controls)
|
return container.NewPadded(controls)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user