Add static UI noise overlay

This commit is contained in:
Stu Leak 2026-01-07 15:02:28 -05:00
parent d30229dfae
commit 306d581c69
2 changed files with 99 additions and 7 deletions

83
internal/ui/noise.go Normal file
View File

@ -0,0 +1,83 @@
package ui
import (
"image"
"image/color"
"math/rand"
"os"
"strings"
"sync"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
)
const (
noiseTileSize = 128
noiseAlpha = uint8(8) // ~3% opacity
noiseVariance = uint8(6) // low contrast
noiseMeanValue = uint8(128)
)
var (
noiseOnce sync.Once
noiseTile *image.NRGBA
uiTextureEnabled = true
)
func init() {
switch strings.ToLower(strings.TrimSpace(os.Getenv("VT_UI_TEXTURE"))) {
case "0", "false", "off", "no":
uiTextureEnabled = false
}
}
// NoisyBackgroundObjects returns background layers with an optional static noise overlay.
func NoisyBackgroundObjects(bg fyne.CanvasObject) []fyne.CanvasObject {
if !uiTextureEnabled {
return []fyne.CanvasObject{bg}
}
return []fyne.CanvasObject{bg, NewNoiseOverlay()}
}
// NewNoiseOverlay creates a static, cached grayscale noise layer.
func NewNoiseOverlay() fyne.CanvasObject {
return canvas.NewRaster(func(w, h int) image.Image {
if w <= 0 || h <= 0 {
return image.NewNRGBA(image.Rect(0, 0, 1, 1))
}
tile := getNoiseTile()
dst := image.NewNRGBA(image.Rect(0, 0, w, h))
tw := tile.Bounds().Dx()
th := tile.Bounds().Dy()
for y := 0; y < h; y++ {
ty := y % th
for x := 0; x < w; x++ {
tx := x % tw
dst.SetNRGBA(x, y, tile.NRGBAAt(tx, ty))
}
}
return dst
})
}
func getNoiseTile() *image.NRGBA {
noiseOnce.Do(func() {
tile := image.NewNRGBA(image.Rect(0, 0, noiseTileSize, noiseTileSize))
rng := rand.New(rand.NewSource(1))
for y := 0; y < noiseTileSize; y++ {
for x := 0; x < noiseTileSize; x++ {
delta := int(rng.Intn(int(noiseVariance)*2+1)) - int(noiseVariance)
v := int(noiseMeanValue) + delta
if v < 0 {
v = 0
} else if v > 255 {
v = 255
}
tile.SetNRGBA(x, y, color.NRGBA{R: uint8(v), G: uint8(v), B: uint8(v), A: noiseAlpha})
}
}
noiseTile = tile
})
return noiseTile
}

23
main.go
View File

@ -6943,7 +6943,9 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
widget.NewSeparator(),
content,
)
return container.NewMax(bg, container.NewPadded(body))
layers := ui.NoisyBackgroundObjects(bg)
layers = append(layers, container.NewPadded(body))
return container.NewMax(layers...)
}
sectionGap := func() fyne.CanvasObject {
@ -10268,7 +10270,9 @@ func makeLabeledPanel(title, body string, min fyne.Size) *fyne.Container {
desc.Wrapping = fyne.TextWrapWord
box := container.NewVBox(header, desc, layout.NewSpacer())
return container.NewMax(rect, container.NewPadded(box))
layers := ui.NoisyBackgroundObjects(rect)
layers = append(layers, container.NewPadded(box))
return container.NewMax(layers...)
}
func buildMetadataPanel(state *appState, src *videoSource, min fyne.Size) (fyne.CanvasObject, func()) {
@ -10289,7 +10293,9 @@ func buildMetadataPanel(state *appState, src *videoSource, min fyne.Size) (fyne.
widget.NewLabel("Load a clip to inspect its technical details."),
layout.NewSpacer(),
)
return container.NewMax(outer, container.NewPadded(body)), func() {}
layers := ui.NoisyBackgroundObjects(outer)
layers = append(layers, container.NewPadded(body))
return container.NewMax(layers...), func() {}
}
bitrate := "--"
@ -10649,7 +10655,9 @@ Metadata: %s`,
)
scroll := container.NewVScroll(body)
scroll.SetMinSize(fyne.NewSize(0, 220))
return container.NewMax(outer, container.NewPadded(scroll)), updateCoverDisplay
layers := ui.NoisyBackgroundObjects(outer)
layers = append(layers, container.NewPadded(scroll))
return container.NewMax(layers...), updateCoverDisplay
}
func buildVideoPane(state *appState, min fyne.Size, src *videoSource, onCover func(string)) fyne.CanvasObject {
@ -15313,7 +15321,9 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
widget.NewSeparator(),
content,
)
return container.NewMax(bg, container.NewPadded(body))
layers := ui.NoisyBackgroundObjects(bg)
layers = append(layers, container.NewPadded(body))
return container.NewMax(layers...)
}
// Scaling (method + blur)
@ -15936,8 +15946,7 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
mainContent := split
content := container.NewMax(
canvas.NewRectangle(mediumBlue),
container.NewPadded(mainContent),
append(ui.NoisyBackgroundObjects(canvas.NewRectangle(mediumBlue)), container.NewPadded(mainContent))...,
)
actionBar := container.NewHBox(layout.NewSpacer(), applyBtn, addQueueBtn)