Skip to content

Commit

Permalink
improving subtitles
Browse files Browse the repository at this point in the history
  • Loading branch information
bquenin committed Jul 27, 2022
1 parent e0d9e0d commit d4aacef
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 41 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,11 @@ translator:
api: "google" # "google" or "deepl"
to: "en" # Target language. For Google translate, please check here: https://cloud.google.com/translate/docs/languages. For deepL, please check here: https://www.deepl.com/en/docs-api/translating-text
authentication-key: "deepl-auth-key" # required only for deepL
subs:
font:
color: "#FFFFFF" # RGB color code
size: 48 # Font size
background:
color: "#404040" # RGB color code
opacity: 0xD0 # Between 0x00 (transparent) and 0xFF (opaque)
```
65 changes: 65 additions & 0 deletions cmd/interpreter/configuration/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ package configuration

import (
_ "embed"
"fmt"
"image/color"
"os"
"path/filepath"
"strings"
"time"

"github.com/bquenin/interpreter/internal/translate"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
)
Expand All @@ -24,11 +27,27 @@ type Translator struct {
AuthenticationKey string `mapstructure:"authentication-key"`
}

type Subs struct {
Font Font `mapstructure:"font"`
Background Background `mapstructure:"background"`
}

type Font struct {
Color string `mapstructure:"color"`
Size int `mapstructure:"size"`
}

type Background struct {
Color string `mapstructure:"color"`
Opacity int `mapstructure:"opacity"`
}

type Configuration struct {
WindowTitle string `mapstructure:"window-title"`
RefreshRate string `mapstructure:"refresh-rate"`
ConfidenceThreshold float32 `mapstructure:"confidence-threshold"`
Translator Translator `mapstructure:"translator"`
Subs Subs `mapstructure:"subs"`
Debug bool
}

Expand Down Expand Up @@ -80,3 +99,49 @@ func (c *Configuration) GetRefreshRate() time.Duration {
}
return refreshRate
}

func (c *Configuration) GetTranslator() (translate.Translator, error) {
var translator translate.Translator
var err error
switch c.Translator.API {
case "google":
translator, err = translate.NewGoogle(c.Translator.To)
case "deepl":
translator, err = translate.NewDeepL(c.Translator.To, c.Translator.AuthenticationKey)
default:
log.Fatal().Msgf("unsupported translator api: %s", c.Translator.API)
}
if err != nil {
return nil, err
}
return translator, nil
}

func parseColorString(s string) (color.RGBA, error) {
var c color.RGBA
if len(s) != 7 {
return c, fmt.Errorf("color string length must be 7 but is %d", len(s))
}
if _, err := fmt.Sscanf(s, "#%02x%02x%02x", &c.R, &c.G, &c.B); err != nil {
return c, fmt.Errorf("unable to parse color string %s", s)
}
return c, nil
}

func (f *Font) GetColor() (color.RGBA, error) {
color, err := parseColorString(f.Color)
if err != nil {
return color, fmt.Errorf("invalid `subs.font.color` value: %w", err)
}
color.A = uint8(0xFF)
return color, nil
}

func (b *Background) GetColor() (color.RGBA, error) {
color, err := parseColorString(b.Color)
if err != nil {
return color, fmt.Errorf("invalid `subs.background.color` value: %w", err)
}
color.A = uint8(b.Opacity)
return color, nil
}
7 changes: 7 additions & 0 deletions cmd/interpreter/configuration/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,10 @@ translator:
api: "google" # "google" or "deepl"
to: "en" # Target language. For Google translate, please check here: https://cloud.google.com/translate/docs/languages. For deepL, please check here: https://www.deepl.com/en/docs-api/translating-text
authentication-key: "deepl-auth-key" # required only for deepL
subs:
font:
color: "#FFFFFF" # RGB color code
size: 48 # Font size
background:
color: "#404040" # RGB color code
opacity: 0xD0 # Between 0x00 (transparent) and 0xFF (opaque)
82 changes: 51 additions & 31 deletions cmd/interpreter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import (
"errors"
"flag"
"fmt"
"github.com/spf13/viper"
"image"
"image/color"
"image/jpeg"
"os"
"strings"
"time"

"cloud.google.com/go/vision/apiv1"
Expand All @@ -24,6 +24,7 @@ import (
"github.com/k0kubun/pp/v3"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
"golang.org/x/image/font"
"golang.org/x/image/font/opentype"
visionpb "google.golang.org/genproto/googleapis/cloud/vision/v1"
Expand All @@ -45,6 +46,8 @@ type App struct {
confidenceThreshold float32
translator translate.Translator
debug bool
subsFontColor color.RGBA
subsBackgroundColor color.RGBA
}

func filterTextByConfidence(annotation *visionpb.TextAnnotation, threshold float32) string {
Expand Down Expand Up @@ -161,41 +164,41 @@ func (a *App) Update() error {
}

func (a *App) Draw(screen *ebiten.Image) {
const x, y = 20, 96
bound := text.BoundString(a.subsFont, a.subs)
ebitenutil.DrawRect(screen, float64(bound.Min.X+x), float64(bound.Min.Y+y), float64(bound.Dx()), float64(bound.Dy()), color.RGBA{R: 0x40, G: 0x40, B: 0x40, A: 0xFF})
text.Draw(screen, a.subs, a.subsFont, x, y, color.White)
if a.subs == "" {
return
}

width, _ := ebiten.ScreenSizeInFullscreen()
var line, subtitles bytes.Buffer
for _, word := range strings.Fields(a.subs) {
bound := text.BoundString(a.subsFont, line.String()+word)
if bound.Dx() > width {
subtitles.WriteString(line.String())
subtitles.WriteString("\n")
line = bytes.Buffer{}
}
line.WriteString(word)
line.WriteString(" ")
}
subtitles.WriteString(line.String())

bound := text.BoundString(a.subsFont, subtitles.String())
boxSize := image.Point{X: bound.Max.X, Y: bound.Dy() + a.subsFont.Metrics().Height.Round()}

x := 0
if boxSize.X < width {
x = (width - boxSize.X) / 2
}
ebitenutil.DrawRect(screen, float64(x), float64(0), float64(boxSize.X), float64(boxSize.Y), a.subsBackgroundColor)
text.Draw(screen, subtitles.String(), a.subsFont, x, a.subsFont.Metrics().Height.Round(), a.subsFontColor)
ebiten.SetWindowSize(width, boxSize.Y)
}

func (a *App) Layout(outsideWidth, outsideHeight int) (int, int) {
return outsideWidth, outsideHeight
}

func NewTranslator(config *configuration.Configuration) (translate.Translator, error) {
var translator translate.Translator
var err error
switch config.Translator.API {
case "google":
translator, err = translate.NewGoogle(config.Translator.To)
case "deepl":
translator, err = translate.NewDeepL(config.Translator.To, config.Translator.AuthenticationKey)
default:
log.Fatal().Msgf("unsupported translator api: %s", config.Translator.API)
}
if err != nil {
return nil, err
}
return translator, nil
}

func main() {
width, height := ebiten.ScreenSizeInFullscreen()
ebiten.SetWindowSize(width, height*20/100)
ebiten.SetWindowTitle("Interpreter")
ebiten.SetWindowDecorated(false)
ebiten.SetWindowFloating(true)
ebiten.SetScreenTransparent(true)

// Read configuration
config, err := configuration.Read()
if err != nil {
Expand Down Expand Up @@ -227,30 +230,47 @@ func main() {
defer visionClient.Close()

// Translator
translator, err := NewTranslator(config)
translator, err := config.GetTranslator()
if err != nil {
log.Fatal().Err(err).Send()
}
defer translator.Close()

// Font
fontColor, err := config.Subs.Font.GetColor()
if err != nil {
log.Fatal().Err(err).Send()
}

backgroundColor, err := config.Subs.Background.GetColor()
if err != nil {
log.Fatal().Err(err).Send()
}

ttf, err := opentype.Parse(fonts.MPlus1pRegular_ttf)
if err != nil {
log.Fatal().Err(err).Send()
}
fontFace, err := opentype.NewFace(ttf, &opentype.FaceOptions{
Size: 48,
Size: float64(config.Subs.Font.Size),
DPI: 72,
Hinting: font.HintingFull,
})
if err != nil {
log.Fatal().Err(err).Send()
}

ebiten.SetWindowTitle("Interpreter")
ebiten.SetWindowDecorated(false)
ebiten.SetWindowFloating(true)
ebiten.SetScreenTransparent(true)

app := &App{
visionClient: visionClient,
translator: translator,
subsFont: fontFace,
subsFontColor: fontColor,
subsBackgroundColor: backgroundColor,
windowTitle: config.WindowTitle,
refreshRate: config.GetRefreshRate(),
confidenceThreshold: config.ConfidenceThreshold,
Expand Down
7 changes: 7 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,10 @@ translator:
api: "google" # "google" or "deepl"
to: "en" # Target language. For Google translate, please check here: https://cloud.google.com/translate/docs/languages. For deepL, please check here: https://www.deepl.com/en/docs-api/translating-text
authentication-key: "deepl-auth-key" # required only for deepL
subs:
font:
color: "#FFFFFF" # RGB color code
size: 48 # Font size
background:
color: "#404040" # RGB color code
opacity: 0xD0 # Between 0x00 (transparent) and 0xFF (opaque)
20 changes: 10 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ require (
github.com/k0kubun/pp/v3 v3.1.0
github.com/rs/zerolog v1.27.0
github.com/spf13/viper v1.12.0
golang.org/x/image v0.0.0-20220617043117-41969df76e82
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539
golang.org/x/text v0.3.7
google.golang.org/genproto v0.0.0-20220715211116-798f69b842b9
google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b
)

require (
Expand All @@ -36,19 +36,19 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.2 // indirect
github.com/spf13/afero v1.9.0 // indirect
github.com/spf13/afero v1.9.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.0 // indirect
go.opencensus.io v0.23.0 // indirect
golang.org/x/exp/shiny v0.0.0-20220713135740-79cabaa25d75 // indirect
golang.org/x/mobile v0.0.0-20220518205345-8578da9835fd // indirect
golang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirect
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 // indirect
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
google.golang.org/api v0.87.0 // indirect
golang.org/x/exp/shiny v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105 // indirect
golang.org/x/net v0.0.0-20220726230323-06994584191e // indirect
golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
google.golang.org/api v0.89.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/grpc v1.48.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
Expand Down
Loading

0 comments on commit d4aacef

Please sign in to comment.