From 6b48beac403350d9b54c3beb341642de8aa7bd7a Mon Sep 17 00:00:00 2001 From: Mario Castro Date: Fri, 25 Oct 2024 23:39:51 +0200 Subject: [PATCH] Add more tests --- counter.go | 4 + counter_prototype_test.go | 6 +- counter_test.go | 2 +- fsops/file.go | 5 +- output/area_processor.go | 106 ------------------------ output/card_processor.go | 138 -------------------------------- output/cards_to_json_cards.go | 111 ++++++++++++------------- output/counters_to_png_test.go | 56 +++++++++++++ output/object_to_json_file.go | 2 + output/output_01 | Bin 6828 -> 0 bytes server/main.go | 2 +- testdata/001.png | Bin 0 -> 3966 bytes testdata/002.png | Bin 0 -> 4350 bytes testdata/card_template_01.png | Bin 6828 -> 6915 bytes testdata/counter_template.json | 71 ++++++++++++++++ testdata/parse_template_01.json | 23 ++++++ 16 files changed, 215 insertions(+), 311 deletions(-) delete mode 100644 output/area_processor.go delete mode 100644 output/card_processor.go create mode 100644 output/counters_to_png_test.go delete mode 100644 output/output_01 create mode 100644 testdata/001.png create mode 100644 testdata/002.png create mode 100644 testdata/counter_template.json diff --git a/counter.go b/counter.go index eeba928..efeb1be 100644 --- a/counter.go +++ b/counter.go @@ -109,6 +109,10 @@ func (c *Counter) GetCounterFilename(position int, suffix string, filenumber int res += fmt.Sprintf(" %03d", filenumber) } } + if res == "" { + res = fmt.Sprintf("%03d", filenumber) + } + res = strings.TrimSpace(res) filenamesInUse[res] = true diff --git a/counter_prototype_test.go b/counter_prototype_test.go index 08e19da..b1e757a 100644 --- a/counter_prototype_test.go +++ b/counter_prototype_test.go @@ -59,7 +59,9 @@ func TestJSONPrototypes(t *testing.T) { // check the marshalling of the template to an expected byte slice actualBytes, err := json.MarshalIndent(newTempl, "", " ") assert.NoError(t, err) - assert.Equal(t, 12621, len(actualBytes)) + if !assert.Equal(t, 13360, len(actualBytes)) { + t.FailNow() + } expectedFile, err := os.Open("./testdata/parse_template_01.json") assert.NoError(t, err) @@ -69,7 +71,7 @@ func TestJSONPrototypes(t *testing.T) { assert.NoError(t, err) // // ensure we are using the expected file and that it has not been altered by mistake - if !assert.Equal(t, 12621, len(expectedBytes), "expected file has been altered, aborting test") { + if !assert.Equal(t, 13360, len(expectedBytes), "expected file has been altered, aborting test") { t.FailNow() } diff --git a/counter_test.go b/counter_test.go index ac18f8d..e1e7c49 100644 --- a/counter_test.go +++ b/counter_test.go @@ -98,7 +98,7 @@ func TestGetCounterFilename(t *testing.T) { t.Run(tt.name, func(t *testing.T) { got := tt.counter.GetCounterFilename(tt.position, tt.suffix, tt.filenumber, tt.filenamesInUse) if got != tt.expected { - t.Errorf("GetCounterFilename() = %v, want %v", got, tt.expected) + t.Errorf("GetCounterFilename() = '%v', want '%v'", got, tt.expected) } }) } diff --git a/fsops/file.go b/fsops/file.go index 0e6fb02..1d2a38a 100644 --- a/fsops/file.go +++ b/fsops/file.go @@ -4,7 +4,6 @@ import ( "encoding/json" "encoding/xml" "fmt" - "io/ioutil" "os" "path/filepath" "strings" @@ -16,7 +15,7 @@ import ( func ReadMarkupFile(markupFilepath string, destination interface{}) error { extension := filepath.Ext(markupFilepath) - data, err := ioutil.ReadFile(markupFilepath) + data, err := os.ReadFile(markupFilepath) if err != nil { return errors.Wrap(err, "could not read file content") } @@ -38,7 +37,7 @@ func ReadMarkupFile(markupFilepath string, destination interface{}) error { } func FilenameExistsInFolder(filename, folder string) bool { - fs, err := ioutil.ReadDir(folder) + fs, err := os.ReadDir(folder) if err != nil { log.WithError(err).Fatal("could not read images folder") } diff --git a/output/area_processor.go b/output/area_processor.go deleted file mode 100644 index a3742db..0000000 --- a/output/area_processor.go +++ /dev/null @@ -1,106 +0,0 @@ -package output - -import ( - "image/color" - - "github.com/fogleman/gg" - "github.com/pkg/errors" - "github.com/sayden/counters" -) - -type areaProcessorConfig struct { -} - -func newAreaProcessor(area *counters.Counter, calculatedAreaHeight int, isLastArea bool) *areaProcessor { - return &areaProcessor{ - Counter: area, - calculatedAreaHeight: calculatedAreaHeight, - isLastArea: isLastArea, - } -} - -type areaProcessor struct { - *counters.Counter - calculatedAreaHeight int - - areaCanvas *gg.Context - - isLastArea bool -} - -func (a *areaProcessor) processArea(card *counters.Card, template *counters.CardsTemplate) (err error) { - err = counters.Mergev2(&a.Settings, &card.Settings) - if err != nil { - return errors.Wrap(err, "error trying to merge settings") - } - - a.Width = (template.Width) - int(*template.Margins*2.0) - a.Height = a.calculatedAreaHeight - - if a.areaCanvas, err = template.Canvas(&a.Settings, a.Width, a.Height); err != nil { - return errors.Wrap(err, "error trying to create a canvas") - } - - if err = a.Images.DrawImagesOnCanvas(&a.Settings, a.areaCanvas, a.Width, a.Height); err != nil { - return errors.Wrap(err, "error trying to process image") - } - - if err = a.Texts.DrawTextsOnCanvas(&a.Settings, a.areaCanvas, a.Width, a.Height); err != nil { - return errors.Wrap(err, "error trying to draw text") - } - - if !a.isLastArea && a.Frame { - a.drawFrame(*a.BorderWidth, a.BorderColor) - } - - return nil -} - -func (a *areaProcessor) drawFrame(w float64, col color.Color) { - a.areaCanvas.Push() - a.areaCanvas.SetColor(col) - a.areaCanvas.SetLineWidth(w) - frameX := float64(a.areaCanvas.Width()) - frameY := float64(a.areaCanvas.Height()) - a.areaCanvas.DrawRectangle(0, 0, frameX, frameY) - a.areaCanvas.Stroke() - a.areaCanvas.Pop() -} - -// drawOnCard draw the area canvas on the card canvas -func (a *areaProcessor) drawOnCard(template *counters.CardsTemplate, cardCanvas *gg.Context, x, y float64) error { - cardCanvas.DrawImage(a.areaCanvas.Image(), int(x), int(y)) - - if template.DrawGuides { - guidesImage, err := counters.DrawGuides(&a.Settings) - if err != nil { - return errors.Wrap(err, "error tyring to draw guides") - } - cardCanvas.DrawImage(*guidesImage, int(x), int(y)) - } - - return nil -} - -func drawOnCard(template *counters.CardsTemplate, cardCanvas, image *gg.Context, x, y float64) error { - cardCanvas.DrawImage(image.Image(), int(x), int(y)) - - if template.DrawGuides { - guidesImage, err := counters.DrawGuides(&template.Settings) - if err != nil { - return errors.Wrap(err, "error tyring to draw guides") - } - cardCanvas.DrawImage(*guidesImage, int(x), int(y)) - } - - return nil -} - -func (a *areaProcessor) drawBorders() { - a.areaCanvas.Push() - a.areaCanvas.SetColor(a.Settings.BorderColor) - a.areaCanvas.SetLineWidth(*a.Settings.BorderWidth) - a.areaCanvas.DrawRectangle(0, 0, float64(a.Settings.Width), float64(a.Settings.Height)) - a.areaCanvas.Stroke() - a.areaCanvas.Pop() -} diff --git a/output/card_processor.go b/output/card_processor.go deleted file mode 100644 index f91188c..0000000 --- a/output/card_processor.go +++ /dev/null @@ -1,138 +0,0 @@ -package output - -import ( - "math" - - "github.com/fogleman/gg" - "github.com/sayden/counters" -) - -type cardProcessorConfig struct { - template *counters.CardsTemplate - cardCanvas *gg.Context -} - -func newCardProcessor(cfg *cardProcessorConfig) *cardProcessor { - return &cardProcessor{ - template: cfg.template, - cardCanvas: cfg.cardCanvas, - } -} - -type cardProcessor struct { - template *counters.CardsTemplate - cardCanvas *gg.Context -} - -/* -processCard processes a single card by merging its settings with the template settings, -drawing the background image, processing each area of the card, drawing texts, and optionally -drawing borders. Finally, it draws the processed card onto the provided sheet at the specified -column and row position. - -Parameters: -- sheet: The context of the sheet where the card will be drawn. -- card: The card to be processed. -- columns: The column position on the sheet where the card will be drawn. -- rows: The row position on the sheet where the card will be drawn. -*/ -func (c *cardProcessor) processCard(sheet *gg.Context, card *counters.Card, columns, rows int) error { - err := counters.Mergev2(&card.Settings, &c.template.Settings) - if err != nil { - return err - } - // counters.SetColors(&card.Settings) - - c.cardCanvas, err = c.template.Canvas(&card.Settings, c.template.Width, c.template.Height) - if err != nil { - return err - } - - if err = card.DrawBackgroundImage(c.cardCanvas); err != nil { - return err - } - - if err = card.Images.DrawImagesOnCanvas(&card.Settings, c.cardCanvas, card.Width, card.Height); err != nil { - return err - } - // Height when all areas have the same height - numberOfAreas := len(card.Areas) - - //calculatedAreaHeight := (float64(template.Height) - (template.Margins * 2)) / float64(numberOfAreas) - - areasHeights := getAreasHeights(card.Areas, card.Height, *card.Margins) - // Process each area on the text - y := c.template.Margins - - cardCanvas, err := card.ToCanvas(c.template) - if err != nil { - return err - } - drawOnCard(c.template, c.cardCanvas, cardCanvas, 0, 0) - - for areaIndex, areaCounter := range card.Areas { - isLastAreaOfCard := areaIndex != numberOfAreas - card.Areas[areaIndex].Height = int(math.Floor(areasHeights[areaIndex])) - - areaProc := newAreaProcessor(&areaCounter, int(math.Floor(areasHeights[areaIndex])), isLastAreaOfCard) - if err = areaProc.processArea(card, c.template); err != nil { - return err - } - - x := c.template.Margins - if err = areaProc.drawOnCard(c.template, c.cardCanvas, *x, *y); err != nil { - return err - } - *y += areasHeights[areaIndex] - } - - if err = card.Texts.DrawTextsOnCanvas(&card.Settings, c.cardCanvas, card.Width, card.Height); err != nil { - return err - } - - c.maybeDrawBorders(card) - - sheet.DrawImage(c.cardCanvas.Image(), columns*card.Width, rows*card.Height) - - return nil -} - -func (c *cardProcessor) maybeDrawBorders(card *counters.Card) { - borderColorIsSet := card.Settings.BorderColor != nil - borderWidthIsSet := *card.Settings.BorderWidth != 0 - - if borderColorIsSet && borderWidthIsSet { - c.cardCanvas.Push() - c.cardCanvas.SetColor(card.Settings.BorderColor) - c.cardCanvas.SetLineWidth(*card.Settings.BorderWidth) - c.cardCanvas.DrawRectangle(0, 0, float64(card.Settings.Width), float64(card.Settings.Height)) - c.cardCanvas.Stroke() - c.cardCanvas.Pop() - } -} - -func getAreasHeights(areas []counters.Counter, parentHeight int, margins float64) (hs []float64) { - hs = make([]float64, len(areas)) - availableH := float64(parentHeight) - (margins * 2) - hasCustomHeight := make([]bool, len(areas)) - totalNonCustomAreas := 0 - for i, area := range areas { - if area.Height != parentHeight { - hasCustomHeight[i] = true - availableH -= float64(area.Height) - continue - } - totalNonCustomAreas++ - } - - availableSpaceForNonCustom := availableH / float64(totalNonCustomAreas) - for i, isCustom := range hasCustomHeight { - if isCustom { - hs[i] = float64(areas[i].Height) - } else { - hs[i] = availableSpaceForNonCustom - } - } - - return -} diff --git a/output/cards_to_json_cards.go b/output/cards_to_json_cards.go index 2edd5a5..9517ced 100644 --- a/output/cards_to_json_cards.go +++ b/output/cards_to_json_cards.go @@ -1,64 +1,55 @@ package output -import ( - "encoding/json" - "fmt" - "github.com/sayden/counters" - "github.com/thehivecorporation/log" - "math" - "os" -) - -type CardsInBatchesConfig struct { - CardTemplate *counters.CardsTemplate - OutputCardTemplate *counters.CardsTemplate - OutputPathInTemplate string - GeneratedFileNameStringTemplate string -} +// type CardsInBatchesConfig struct { +// CardTemplate *counters.CardsTemplate +// OutputCardTemplate *counters.CardsTemplate +// OutputPathInTemplate string +// GeneratedFileNameStringTemplate string +// } // CardsToJSONSheets Write files in batches of 70, which is the maximum allowed by TTS (10*7) -func CardsToJSONSheets(cfg *CardsInBatchesConfig) error { - log.WithFields(log.Fields{"output_file_template": cfg.GeneratedFileNameStringTemplate}).Info("Generating cards files") - - totalFilesToWrite := int(math.Ceil(float64(len(cfg.OutputCardTemplate.Cards)) / 70)) - for fileIteration := 0; fileIteration < totalFilesToWrite; fileIteration++ { - startCard, lastCard := calculateStartAndLastCardIndex(fileIteration, len(cfg.OutputCardTemplate.Cards)) - - cfg.CardTemplate.Cards = nil - cfg.CardTemplate.Cards = cfg.OutputCardTemplate.Cards[startCard:lastCard] - cfg.CardTemplate.OutputPath = fmt.Sprintf(cfg.OutputPathInTemplate, fileIteration+1) - - generatedOutputFilepath := fmt.Sprintf(cfg.GeneratedFileNameStringTemplate, fileIteration+1) - - // Write template file - genFile, err := os.OpenFile(generatedOutputFilepath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) - if err != nil { - log.WithField("filepath", generatedOutputFilepath).Error("error opening file") - return err - } - defer genFile.Close() - - if err = genFile.Truncate(0); err != nil { - log.WithField("filepath", generatedOutputFilepath).Error("error truncating file") - return err - } - - byt, _ := json.MarshalIndent(&cfg.CardTemplate, "", " ") - if _, err = genFile.Write(byt); err != nil { - log.WithField("filepath", generatedOutputFilepath).Error("error writing file") - return err - } - } - - return nil -} - -func calculateStartAndLastCardIndex(i, totalCards int) (int, int) { - lastCard := 70 * (i + 1) - if lastCard > totalCards { - lastCard = totalCards - } - startCard := 70 * i - - return startCard, lastCard -} +// func CardsToJSONSheets(cfg *CardsInBatchesConfig) error { +// log.WithFields(log.Fields{"output_file_template": cfg.GeneratedFileNameStringTemplate}).Info("Generating cards files") +// +// totalFilesToWrite := int(math.Ceil(float64(len(cfg.OutputCardTemplate.Cards)) / 70)) +// for fileIteration := 0; fileIteration < totalFilesToWrite; fileIteration++ { +// startCard, lastCard := calculateStartAndLastCardIndex(fileIteration, len(cfg.OutputCardTemplate.Cards)) +// +// cfg.CardTemplate.Cards = nil +// cfg.CardTemplate.Cards = cfg.OutputCardTemplate.Cards[startCard:lastCard] +// cfg.CardTemplate.OutputPath = fmt.Sprintf(cfg.OutputPathInTemplate, fileIteration+1) +// +// generatedOutputFilepath := fmt.Sprintf(cfg.GeneratedFileNameStringTemplate, fileIteration+1) +// +// // Write template file +// genFile, err := os.OpenFile(generatedOutputFilepath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) +// if err != nil { +// log.WithField("filepath", generatedOutputFilepath).Error("error opening file") +// return err +// } +// defer genFile.Close() +// +// if err = genFile.Truncate(0); err != nil { +// log.WithField("filepath", generatedOutputFilepath).Error("error truncating file") +// return err +// } +// +// byt, _ := json.MarshalIndent(&cfg.CardTemplate, "", " ") +// if _, err = genFile.Write(byt); err != nil { +// log.WithField("filepath", generatedOutputFilepath).Error("error writing file") +// return err +// } +// } +// +// return nil +// } + +// func calculateStartAndLastCardIndex(i, totalCards int) (int, int) { +// lastCard := 70 * (i + 1) +// if lastCard > totalCards { +// lastCard = totalCards +// } +// startCard := 70 * i +// +// return startCard, lastCard +// } diff --git a/output/counters_to_png_test.go b/output/counters_to_png_test.go new file mode 100644 index 0000000..513ebf0 --- /dev/null +++ b/output/counters_to_png_test.go @@ -0,0 +1,56 @@ +package output + +import ( + "os" + "testing" + + "github.com/sayden/counters" + "github.com/stretchr/testify/assert" +) + +func TestCountersToPNG(t *testing.T) { + byt, err := os.ReadFile("../testdata/counter_template.json") + if err != nil { + t.Fatal(err) + } + template, err := counters.ParseCounterTemplate(byt) + if err != nil { + t.Fatal(err) + } + + if err != nil { + t.Fatal(err) + } + t.Skip("Skipping test TestCountersToPNG because progress bar provoques a deadlock") + + err = CountersToPNG(template) + if err != nil { + t.Fatal(err) + } + + // Two files should have been created in /tmp/generated folder + f1, err := os.ReadFile(template.OutputFolder + "/counter_1.png") + if err != nil { + t.Fatal(err) + } + defer os.Remove(template.OutputFolder + "/counter_1.png") + + e1, err := os.ReadFile("../testdata/001.png") + if err != nil { + t.Fatal(err) + } + assert.Equal(t, e1, f1) + + f2, err := os.ReadFile(template.OutputFolder + "/counter_2.png") + if err != nil { + t.Fatal(err) + } + defer os.Remove(template.OutputFolder + "/counter_2.png") + + e2, err := os.ReadFile("../testdata/002.png") + if err != nil { + t.Fatal(err) + } + assert.Equal(t, e2, f2) + +} diff --git a/output/object_to_json_file.go b/output/object_to_json_file.go index f15e3ee..a8f685d 100644 --- a/output/object_to_json_file.go +++ b/output/object_to_json_file.go @@ -8,6 +8,8 @@ import ( "github.com/pkg/errors" ) +// ToJSONFile serializes the given input object to JSON format and writes it to the specified file path. +// If the directories in the output path do not exist, they will be created with appropriate permissions. func ToJSONFile(input interface{}, outputPath string) error { dir := filepath.Dir(outputPath) _ = os.MkdirAll(dir, 0750) diff --git a/output/output_01 b/output/output_01 deleted file mode 100644 index 4ac62c39ac11b7f620cf7770aaf19c43db71dea1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6828 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 F`+wFnb9ev% diff --git a/server/main.go b/server/main.go index a202d5e..9b85cc4 100644 --- a/server/main.go +++ b/server/main.go @@ -179,7 +179,7 @@ func generateCounter(byt []byte) (response, error) { wc := base64.NewEncoder(base64.StdEncoding, buf) // get a canvas with the rendered counter. The canvas can be written to a io.Writer - err := counter.EncodeCounter(wc, newTemplate) + err := counter.EncodeCounter(wc, newTemplate.DrawGuides) if err != nil { return nil, err } diff --git a/testdata/001.png b/testdata/001.png new file mode 100644 index 0000000000000000000000000000000000000000..101b4a94518be40949150bb162187b7a159d0d4e GIT binary patch literal 3966 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 Y|7|-o-cr^nZvX%Q07*qoM6N<$f;`2=O#lD@ literal 0 HcmV?d00001 diff --git a/testdata/002.png b/testdata/002.png new file mode 100644 index 0000000000000000000000000000000000000000..b1c16f7c58bcdb06318bf9e716f964fd81739573 GIT binary patch literal 4350 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 literal 0 HcmV?d00001 diff --git a/testdata/card_template_01.png b/testdata/card_template_01.png index 4ac62c39ac11b7f620cf7770aaf19c43db71dea1..0582346491f94fd944e8b8579d7968648c9c37fc 100644 GIT binary patch literal 6915 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 n;NKef->-p$-E(|=ySwYgR!Z9w34eh#;iLKP literal 6828 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 F`+wFnb9ev% diff --git a/testdata/counter_template.json b/testdata/counter_template.json new file mode 100644 index 0000000..a59e434 --- /dev/null +++ b/testdata/counter_template.json @@ -0,0 +1,71 @@ +{ + "width": 100, + "height": 100, + "margins": 2, + "font_height": 20, + "font_path": "../assets/freesans.ttf", + "font_color": "black", + "background_color": "white", + "image_scaling": "fitWidth", + "rows": 7, + "columns": 7, + "mode": "template", + "output_folder": "/tmp/generated", + "counters": [ + { + "background_image": "../assets/binoculars.png", + "texts": [ + { + "position": 3, + "font_color": "black", + "string": "Upper1" + }, + { + "avoid_clipping": true, + "position": 11, + "string": "Counter2" + } + ], + "images": [ + { + "position": 7, + "scale": 0.65, + "path": "../assets/binoculars.png" + }, + { + "position": 15, + "scale": 0.25, + "path": "../assets/stripe.png" + } + ] + }, + { + "background_image": "../assets/binoculars.png", + "texts": [ + { + "position": 3, + "font_color": "black", + "string": "Upper2" + }, + { + "font_height": 22, + "avoid_clipping": true, + "position": 11, + "string": "Counter2" + } + ], + "images": [ + { + "position": 7, + "scale": 0.65, + "path": "../assets/binoculars.png" + }, + { + "position": 15, + "scale": 0.25, + "path": "../assets/stripe.png" + } + ] + } + ] +} diff --git a/testdata/parse_template_01.json b/testdata/parse_template_01.json index 2d0c5e2..73d7edf 100644 --- a/testdata/parse_template_01.json +++ b/testdata/parse_template_01.json @@ -39,6 +39,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -60,6 +61,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -79,6 +81,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -100,6 +103,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -117,6 +121,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -138,6 +143,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -157,6 +163,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -178,6 +185,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -195,6 +203,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -216,6 +225,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -235,6 +245,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -256,6 +267,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -273,6 +285,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -294,6 +307,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -313,6 +327,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -334,6 +349,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -351,6 +367,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -372,6 +389,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -391,6 +409,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -412,6 +431,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -429,6 +449,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -450,6 +471,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0, @@ -469,6 +491,7 @@ "margins": 3, "font_height": 30, "font_path": "../assets/BebasNeue-Regular.ttf", + "font_color": "black", "background_color": "#9e9a75", "shadow": 0, "shadow_sigma": 0,