fixed img-generate in the Patch and some other minor issue

This commit is contained in:
Faraphel 2022-07-05 22:34:10 +02:00
parent 90ab49aa29
commit ca833eca2a
29 changed files with 306 additions and 235 deletions

View file

@ -0,0 +1,3 @@
{
"mode": "ignore"
}

View file

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View file

@ -0,0 +1,3 @@
{
"mode": "ignore"
}

View file

@ -2,19 +2,19 @@
"operation": { "operation": {
"img-generate": { "img-generate": {
"layers": [ "layers": [
{"type": "image", "path": "/specific/bootscreen-base.png"}, {"type": "image", "image_path": "files/Boot/Strap/bootscreen-base.png"},
{"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "text_size": 0.04, "color": [100, 100, 100], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.10, "y": 0.06, "text": "Elke track heeft een score tussen 1 en 5 sterren", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.10, "y": 0.06, "text": "Elke track heeft een score tussen 1 en 5 sterren", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.12, "text": " speelbaar", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.12, "text": " speelbaar", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.35, "y": 0.12, "text": " perfect", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.35, "y": 0.12, "text": " perfect", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.18, "text": " klein probleem", "text_size": 0.045, "color": [255, 130, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.18, "text": " klein probleem", "font_size": 0.045, "color": [255, 130, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.18, "text": " groot probleem", "text_size": 0.045, "color": [255, 50, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.18, "text": " groot probleem", "font_size": 0.045, "color": [255, 50, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.24, "text": " alleen dolphin", "text_size": 0.045, "color": [70, 130, 255], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.24, "text": " alleen dolphin", "font_size": 0.045, "color": [70, 130, 255], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.25, "text": "\"Boost\" betekent dat je constant zult zijn\nversnellen op deze baan", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.25, "text": "\"Boost\" betekent dat je constant zult zijn\nversnellen op deze baan", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.40, "text": "De auteur van het nummer wordt gecrediteerd\nterwijl de race presentatie", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.40, "text": "De auteur van het nummer wordt gecrediteerd\nterwijl de race presentatie", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.67, "text": "Het spel van het originele nummer, indien\ngetoond met het voorvoegsel", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.67, "text": "Het spel van het originele nummer, indien\ngetoond met het voorvoegsel", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.02, "y": 0.88, "text": "Alle scores zijn niet altijd correct, je kunt een bijdrage leveren aan", "text_size": 0.04, "color": [128, 128, 128], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.02, "y": 0.88, "text": "Alle scores zijn niet altijd correct, je kunt een bijdrage leveren aan", "font_size": 0.04, "color": [128, 128, 128], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.02, "y": 0.93, "text": "de mod door je mening te geven over de discord : https://discord.gg/C66cfHBb7S", "text_size": 0.04, "color": [128, 128, 128], "font_path": "/specific/CenturyGothicBold.ttf"} {"type": "text", "x": 0.02, "y": 0.93, "text": "de mod door je mening te geven over de discord : https://discord.gg/C66cfHBb7S", "font_size": 0.04, "color": [128, 128, 128], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}
] ]
} }
} }

View file

@ -2,19 +2,19 @@
"operation": { "operation": {
"img-generate": { "img-generate": {
"layers": [ "layers": [
{"type": "image", "path": "/specific/bootscreen-base.png"}, {"type": "image", "image_path": "files/Boot/Strap/bootscreen-base.png"},
{"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "text_size": 0.04, "color": [100, 100, 100], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.10, "y": 0.06, "text": "Every track has a score between 1 and 5 stars", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.10, "y": 0.06, "text": "Every track has a score between 1 and 5 stars", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.12, "text": " playable", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.12, "text": " playable", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.35, "y": 0.12, "text": " perfect", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.35, "y": 0.12, "text": " perfect", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.18, "text": " minor issue", "text_size": 0.045, "color": [255, 130, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.18, "text": " minor issue", "font_size": 0.045, "color": [255, 130, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.18, "text": " major issue", "text_size": 0.045, "color": [255, 50, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.18, "text": " major issue", "font_size": 0.045, "color": [255, 50, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.24, "text": " dolphin only", "text_size": 0.045, "color": [70, 130, 255], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.24, "text": " dolphin only", "font_size": 0.045, "color": [70, 130, 255], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.25, "text": "\"Boost\" mean that you will be constantly\nbe accelerating on this track", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.25, "text": "\"Boost\" mean that you will be constantly\nbe accelerating on this track", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.40, "text": "The track's author is credited while\nthe track presentation", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.40, "text": "The track's author is credited while\nthe track presentation", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.67, "text": "The original track's game if shown\nwith the prefix", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.67, "text": "The original track's game if shown\nwith the prefix", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.02, "y": 0.88, "text": "All score are not always correct, you can contribute to", "text_size": 0.04, "color": [128, 128, 128], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.02, "y": 0.88, "text": "All score are not always correct, you can contribute to", "font_size": 0.04, "color": [128, 128, 128], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.02, "y": 0.93, "text": "the mod by giving your opinion on the discord : https://discord.gg/C66cfHBb7S", "text_size": 0.04, "color": [128, 128, 128], "font_path": "/specific/CenturyGothicBold.ttf"} {"type": "text", "x": 0.02, "y": 0.93, "text": "the mod by giving your opinion on the discord : https://discord.gg/C66cfHBb7S", "font_size": 0.04, "color": [128, 128, 128], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}
] ]
} }
} }

View file

@ -2,19 +2,19 @@
"operation": { "operation": {
"img-generate": { "img-generate": {
"layers": [ "layers": [
{"type": "image", "path": "/specific/bootscreen-base.png"}, {"type": "image", "image_path": "files/Boot/Strap/bootscreen-base.png"},
{"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "text_size": 0.04, "color": [100, 100, 100], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.10, "y": 0.06, "text": "Cada pista tiene una puntuación entre 1 y 5 estrellas", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.10, "y": 0.06, "text": "Cada pista tiene una puntuación entre 1 y 5 estrellas", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.12, "text": " interpretable", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.12, "text": " interpretable", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.35, "y": 0.12, "text": " perfecto", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.35, "y": 0.12, "text": " perfecto", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.18, "text": " problema menor", "text_size": 0.045, "color": [255, 130, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.18, "text": " problema menor", "font_size": 0.045, "color": [255, 130, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.18, "text": " problema mayor", "text_size": 0.045, "color": [255, 50, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.18, "text": " problema mayor", "font_size": 0.045, "color": [255, 50, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.24, "text": " solo dolphin", "text_size": 0.045, "color": [70, 130, 255], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.24, "text": " solo dolphin", "font_size": 0.045, "color": [70, 130, 255], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.25, "text": "\"Boost\" significa que estarás constantemente\nestar acelerando en esta pista", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.25, "text": "\"Boost\" significa que estarás constantemente\nestar acelerando en esta pista", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.40, "text": "El autor de la pista es acreditado\nmientras presentación de la pista", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.40, "text": "El autor de la pista es acreditado\nmientras presentación de la pista", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.67, "text": "El juego de la pista original\nsi se muestra con el prefijo", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.67, "text": "El juego de la pista original\nsi se muestra con el prefijo", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.02, "y": 0.88, "text": "Todos los puntajes no siempre son correctos, puedes contribuir a", "text_size": 0.04, "color": [128, 128, 128], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.02, "y": 0.88, "text": "Todos los puntajes no siempre son correctos, puedes contribuir a", "font_size": 0.04, "color": [128, 128, 128], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.02, "y": 0.93, "text": "el mod dando tu opinion en el discord : https://discord.gg/C66cfHBb7S", "text_size": 0.04, "color": [128, 128, 128], "font_path": "/specific/CenturyGothicBold.ttf"} {"type": "text", "x": 0.02, "y": 0.93, "text": "el mod dando tu opinion en el discord : https://discord.gg/C66cfHBb7S", "font_size": 0.04, "color": [128, 128, 128], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}
] ]
} }
} }

View file

@ -2,19 +2,19 @@
"operation": { "operation": {
"img-generate": { "img-generate": {
"layers": [ "layers": [
{"type": "image", "path": "/specific/bootscreen-base.png"}, {"type": "image", "image_path": "files/Boot/Strap/bootscreen-base.png"},
{"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "text_size": 0.04, "color": [100, 100, 100], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.10, "y": 0.06, "text": "Chaque course possède une note allant de 1 à 5 étoiles", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.10, "y": 0.06, "text": "Chaque course possède une note allant de 1 à 5 étoiles", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.12, "text": " jouable", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.12, "text": " jouable", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.35, "y": 0.12, "text": " parfait", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.35, "y": 0.12, "text": " parfait", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.18, "text": " problème mineur", "text_size": 0.045, "color": [255, 130, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.18, "text": " problème mineur", "font_size": 0.045, "color": [255, 130, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.18, "text": " problème majeur", "text_size": 0.045, "color": [255, 50, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.18, "text": " problème majeur", "font_size": 0.045, "color": [255, 50, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.24, "text": " seulement dolphin", "text_size": 0.045, "color": [70, 130, 255], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.24, "text": " seulement dolphin", "font_size": 0.045, "color": [70, 130, 255], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.25, "text": "\"Boost\" indique que vous serez constamment\nen accélération sur cette course", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.25, "text": "\"Boost\" indique que vous serez constamment\nen accélération sur cette course", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.40, "text": "L'auteur de la course est affiché lors\nde la présentation de la course", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.40, "text": "L'auteur de la course est affiché lors\nde la présentation de la course", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.67, "text": "Le jeu originel de la course est affiché\nen préfix", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.67, "text": "Le jeu originel de la course est affiché\nen préfix", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.02, "y": 0.88, "text": "Les notes ne sont pas toujours exactes, vous pouvez contribuer", "text_size": 0.04, "color": [128, 128, 128], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.02, "y": 0.88, "text": "Les notes ne sont pas toujours exactes, vous pouvez contribuer", "font_size": 0.04, "color": [128, 128, 128], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.02, "y": 0.93, "text": "au mod en donnant votre avi sur le discord : https://discord.gg/C66cfHBb7S", "text_size": 0.04, "color": [128, 128, 128], "font_path": "/specific/CenturyGothicBold.ttf"} {"type": "text", "x": 0.02, "y": 0.93, "text": "au mod en donnant votre avi sur le discord : https://discord.gg/C66cfHBb7S", "font_size": 0.04, "color": [128, 128, 128], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}
] ]
} }
} }

View file

@ -2,19 +2,19 @@
"operation": { "operation": {
"img-generate": { "img-generate": {
"layers": [ "layers": [
{"type": "image", "path": "/specific/bootscreen-base.png"}, {"type": "image", "image_path": "files/Boot/Strap/bootscreen-base.png"},
{"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "text_size": 0.04, "color": [100, 100, 100], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.10, "y": 0.06, "text": "Jeder track hat eine Punktzahl zwischen 1 und 5 sternen", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.10, "y": 0.06, "text": "Jeder track hat eine Punktzahl zwischen 1 und 5 sternen", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.12, "text": " spielbar", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.12, "text": " spielbar", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.35, "y": 0.12, "text": " perfekt", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.35, "y": 0.12, "text": " perfekt", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.18, "text": " kleines problem", "text_size": 0.045, "color": [255, 130, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.18, "text": " kleines problem", "font_size": 0.045, "color": [255, 130, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.18, "text": " hauptproblem", "text_size": 0.045, "color": [255, 50, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.18, "text": " hauptproblem", "font_size": 0.045, "color": [255, 50, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.24, "text": " nur dolphin", "text_size": 0.045, "color": [70, 130, 255], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.24, "text": " nur dolphin", "font_size": 0.045, "color": [70, 130, 255], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.25, "text": "\"Boost\" bedeutet, dass Sie ständig sein\nwerden auf dieser track beschleunigen", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.25, "text": "\"Boost\" bedeutet, dass Sie ständig sein\nwerden auf dieser track beschleunigen", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.40, "text": "Der Autor des Titels wird dabei\ngenannt die Track-Präsentation", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.40, "text": "Der Autor des Titels wird dabei\ngenannt die Track-Präsentation", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.67, "text": "Das Spiel des Originaltracks, falls\nangezeigt mit dem Präfix", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.67, "text": "Das Spiel des Originaltracks, falls\nangezeigt mit dem Präfix", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.02, "y": 0.88, "text": "Alle Punktzahlen sind nicht immer korrekt, Sie können zum Mod beitragen,", "text_size": 0.04, "color": [128, 128, 128], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.02, "y": 0.88, "text": "Alle Punktzahlen sind nicht immer korrekt, Sie können zum Mod beitragen,", "font_size": 0.04, "color": [128, 128, 128], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.02, "y": 0.93, "text": "indem Sie Ihre Meinung zum Discord äußern : https://discord.gg/C66cfHBb7S", "text_size": 0.04, "color": [128, 128, 128], "font_path": "/specific/CenturyGothicBold.ttf"} {"type": "text", "x": 0.02, "y": 0.93, "text": "indem Sie Ihre Meinung zum Discord äußern : https://discord.gg/C66cfHBb7S", "font_size": 0.04, "color": [128, 128, 128], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}
] ]
} }
} }

View file

@ -2,19 +2,19 @@
"operation": { "operation": {
"img-generate": { "img-generate": {
"layers": [ "layers": [
{"type": "image", "path": "/specific/bootscreen-base.png"}, {"type": "image", "image_path": "files/Boot/Strap/bootscreen-base.png"},
{"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "text_size": 0.04, "color": [100, 100, 100], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.01, "y": 0.00, "text": "Mario Kart Wii - Faraphel", "font_size": 0.04, "color": [100, 100, 100], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.10, "y": 0.06, "text": "Ogni traccia ha un punteggio compreso tra 1 e 5 stelle", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.10, "y": 0.06, "text": "Ogni traccia ha un punteggio compreso tra 1 e 5 stelle", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.12, "text": " giocabile", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.12, "text": " giocabile", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.35, "y": 0.12, "text": " perfetto", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.35, "y": 0.12, "text": " perfetto", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.18, "text": " problema minore", "text_size": 0.045, "color": [255, 130, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.18, "text": " problema minore", "font_size": 0.045, "color": [255, 130, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.18, "text": " problema serio", "text_size": 0.045, "color": [255, 50, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.18, "text": " problema serio", "font_size": 0.045, "color": [255, 50, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.17, "y": 0.24, "text": " solo dolphin", "text_size": 0.045, "color": [70, 130, 255], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.17, "y": 0.24, "text": " solo dolphin", "font_size": 0.045, "color": [70, 130, 255], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.25, "text": "\"Boost\" significa che sarai costantemente\naccelerare su questa pista", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.25, "text": "\"Boost\" significa che sarai costantemente\naccelerare su questa pista", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.40, "text": "L'autore della traccia è accreditato\nmentre la presentazione del brano", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.40, "text": "L'autore della traccia è accreditato\nmentre la presentazione del brano", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.45, "y": 0.67, "text": "Il gioco della traccia originale se\nmostrato con il prefisso", "text_size": 0.045, "color": [255, 180, 0], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.45, "y": 0.67, "text": "Il gioco della traccia originale se\nmostrato con il prefisso", "font_size": 0.045, "color": [255, 180, 0], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.02, "y": 0.88, "text": "Tutti i punteggi non sono sempre corretti, puoi contribuire a", "text_size": 0.04, "color": [128, 128, 128], "font_path": "/specific/CenturyGothicBold.ttf"}, {"type": "text", "x": 0.02, "y": 0.88, "text": "Tutti i punteggi non sono sempre corretti, puoi contribuire a", "font_size": 0.04, "color": [128, 128, 128], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"},
{"type": "text", "x": 0.02, "y": 0.93, "text": "la mod dando la tua opinione sulla discordia : https://discord.gg/C66cfHBb7S", "text_size": 0.04, "color": [128, 128, 128], "font_path": "/specific/CenturyGothicBold.ttf"} {"type": "text", "x": 0.02, "y": 0.93, "text": "la mod dando la tua opinione sulla discordia : https://discord.gg/C66cfHBb7S", "font_size": 0.04, "color": [128, 128, 128], "font_path": "files/Boot/Strap/CenturyGothicBold.ttf"}
] ]
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"operation": { "operation": {
"tpl-encode": { "img-encode": {
"encoding": "TPL.RGB565" "encoding": "TPL.RGB565"
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"operation": { "operation": {
"tpl-encode": { "img-encode": {
"encoding": "TPL.RGB5A3" "encoding": "TPL.RGB5A3"
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"operation": { "operation": {
"tpl-encode": { "img-encode": {
"encoding": "TPL.RGB5A3" "encoding": "TPL.RGB5A3"
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"operation": { "operation": {
"tpl-encode": { "img-encode": {
"encoding": "TPL.RGB5A3" "encoding": "TPL.RGB5A3"
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"operation": { "operation": {
"tpl-encode": { "img-encode": {
"encoding": "TPL.RGB5A3" "encoding": "TPL.RGB5A3"
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"operation": { "operation": {
"tpl-encode": { "img-encode": {
"encoding": "TPL.RGB5A3" "encoding": "TPL.RGB5A3"
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"operation": { "operation": {
"tpl-encode": { "img-encode": {
"encoding": "TPL.RGB5A3" "encoding": "TPL.RGB5A3"
} }
} }

View file

@ -1,6 +1,6 @@
{ {
"operation": { "operation": {
"tpl-encode": { "img-encode": {
"encoding": "TPL.RGB5A3" "encoding": "TPL.RGB5A3"
} }
} }

View file

@ -1,7 +1,7 @@
{ {
"mode": "edit", "mode": "edit",
"operation": { "operation": {
"bmg-replace": { "bmg-edit": {
"mode": "id", "mode": "id",
"data": { "data": {
"0x703e": "\\c{white}Random: All tracks", "0x703e": "\\c{white}Random: All tracks",

View file

@ -1,7 +1,7 @@
{ {
"mode": "edit", "mode": "edit",
"operation": { "operation": {
"bmg-replace": { "bmg-edit": {
"mode": "id", "mode": "id",
"data": { "data": {
"0x703e": "\\c{white}Aleatorio: Todas las pistas", "0x703e": "\\c{white}Aleatorio: Todas las pistas",

View file

@ -1,7 +1,7 @@
{ {
"mode": "edit", "mode": "edit",
"operation": { "operation": {
"bmg-replace": { "bmg-edit": {
"mode": "id", "mode": "id",
"data": { "data": {
"0x703e": "\\c{white}Aléatoire: Toutes les pistes", "0x703e": "\\c{white}Aléatoire: Toutes les pistes",

View file

@ -1,7 +1,7 @@
{ {
"mode": "edit", "mode": "edit",
"operation": { "operation": {
"bmg-replace": { "bmg-edit": {
"mode": "id", "mode": "id",
"data": { "data": {
"0x703e": "\\c{white}Zufällig: Alle Tracks", "0x703e": "\\c{white}Zufällig: Alle Tracks",

View file

@ -1,7 +1,7 @@
{ {
"mode": "edit", "mode": "edit",
"operation": { "operation": {
"bmg-replace": { "bmg-edit": {
"mode": "id", "mode": "id",
"data": { "data": {
"0x703e": "\\c{white}Casuale: Tutte le tracce", "0x703e": "\\c{white}Casuale: Tutte le tracce",

View file

@ -47,6 +47,9 @@ class PatchDirectory(PatchObject):
if game_subfile.suffix == ".szs": game_subfile = game_subfile.with_suffix(".d") if game_subfile.suffix == ".szs": game_subfile = game_subfile.with_suffix(".d")
yield from subpatch.install(extracted_game, game_subfile / subpatch.full_path.name) yield from subpatch.install(extracted_game, game_subfile / subpatch.full_path.name)
# ignore if mode is "ignore", useful if the file is used as a resource for an operation
case "ignore": pass
# else raise an error # else raise an error
case _: case _:
raise InvalidPatchMode(self.configuration["mode"]) raise InvalidPatchMode(self.configuration["mode"])

View file

@ -56,7 +56,7 @@ class PatchFile(PatchObject):
for operation_name, operation in self.configuration.get("operation", {}).items(): for operation_name, operation in self.configuration.get("operation", {}).items():
# process every operation and get the new patch_path (if the name is changed) # process every operation and get the new patch_path (if the name is changed)
# and the new content of the patch # and the new content of the patch
patch_name, patch_content = PatchOperation.Operation(operation_name)(**operation).patch( patch_name, patch_content = PatchOperation(operation_name)(**operation).patch(
self.patch, patch_name, patch_content self.patch, patch_name, patch_content
) )
@ -84,6 +84,9 @@ class PatchFile(PatchObject):
patch_content.seek(0) patch_content.seek(0)
file.write(patch_content.read()) file.write(patch_content.read())
# ignore if mode is "ignore", useful if the file is used as a resource for an operation
case "ignore": pass
# else raise an error # else raise an error
case _: case _:
raise InvalidPatchMode(self.configuration["mode"]) raise InvalidPatchMode(self.configuration["mode"])

View file

@ -56,7 +56,7 @@ class PatchObject(ABC):
from source.mkw.Patch.PatchDirectory import PatchDirectory from source.mkw.Patch.PatchDirectory import PatchDirectory
from source.mkw.Patch.PatchFile import PatchFile from source.mkw.Patch.PatchFile import PatchFile
obj = PatchDirectory.Patch if path.is_dir() else PatchFile obj = PatchDirectory if path.is_dir() else PatchFile
return obj(self.patch, str(path.relative_to(self.patch.path))) return obj(self.patch, str(path.relative_to(self.patch.path)))
@abstractmethod @abstractmethod

View file

@ -5,12 +5,23 @@ from typing import IO
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
from source.mkw.Patch import * from source.mkw.Patch import *
from source.wt.img import IMGPath
class PatchOperation: class PatchOperation:
""" """
Represent an operation that can be applied onto a patch to modify it before installing Represent an operation that can be applied onto a patch to modify it before installing
""" """
def __new__(cls, name) -> "Operation":
"""
Return an operation from its name
:return: an Operation from its name
"""
for subclass in filter(lambda subclass: subclass.type == name, cls.Operation.__subclasses__()):
return subclass
raise InvalidPatchOperation(name)
class Operation(ABC): class Operation(ABC):
@abstractmethod @abstractmethod
def patch(self, patch: "Patch", file_name: str, file_content: IO) -> (str, IO): def patch(self, patch: "Patch", file_name: str, file_content: IO) -> (str, IO):
@ -18,15 +29,6 @@ class PatchOperation:
patch a file and return the new file_path (if changed) and the new content of the file patch a file and return the new file_path (if changed) and the new content of the file
""" """
def __new__(cls, name) -> "Operation":
"""
Return an operation from its name
:return: an Operation from its name
"""
for subclass in filter(lambda subclass: subclass.type == name, cls.__subclasses__()):
return subclass
raise InvalidPatchOperation(name)
class ImageGenerator(Operation): class ImageGenerator(Operation):
""" """
generate a new image based on a file and apply a generator on it generate a new image based on a file and apply a generator on it
@ -49,9 +51,9 @@ class PatchOperation:
return file_name, patch_content return file_name, patch_content
class Layer(ABC): class Layer:
""" """
represent a layer for a image generator represent a layer for an image generator
""" """
def __new__(cls, layer: dict) -> "Layer": def __new__(cls, layer: dict) -> "Layer":
@ -59,152 +61,191 @@ class PatchOperation:
return the correct type of layer corresponding to the layer mode return the correct type of layer corresponding to the layer mode
:param layer: the layer to load :param layer: the layer to load
""" """
for subclass in filter(lambda subclass: subclass.type == layer["type"], cls.__subclasses__()): for subclass in filter(lambda subclass: subclass.type == layer["type"],
cls.AbstractLayer.__subclasses__()):
layer.pop("type") layer.pop("type")
return subclass(**layer) return subclass(**layer)
raise InvalidImageLayerType(layer["type"]) raise InvalidImageLayerType(layer["type"])
def get_bbox(self, image: Image.Image) -> tuple: class AbstractLayer(ABC):
def get_bbox(self, image: Image.Image) -> tuple:
"""
return a tuple of a bbox from x1, x2, y1, y2
if float, calculate the position like a percentage on the image
if int, use directly the position
"""
if isinstance(x1 := self.x1, float): x1 = int(x1 * image.width)
if isinstance(y1 := self.y1, float): y1 = int(y1 * image.height)
if isinstance(x2 := self.x2, float): x2 = int(x2 * image.width)
if isinstance(y2 := self.y2, float): y2 = int(y2 * image.height)
return x1, y1, x2, y2
def get_bbox_size(self, image: Image.Image) -> tuple:
"""
return the size that a layer use on the image
"""
x1, y1, x2, y2 = self.get_bbox(image)
return x2 - x1, y2 - y1
def get_font_size(self, image: Image.Image) -> int:
"""
return the font_size of a layer
"""
return int(self.font_size * image.height) if isinstance(self.font_size, float) else self.font_size
def get_layer_position(self, image: Image.Image) -> tuple:
"""
return a tuple of the x and y position
if x / y is a float, calculate the position like a percentage on the image
if x / y is an int, use directly the position
"""
if isinstance(x := self.x, float): x = int(x * image.width)
if isinstance(y := self.y, float): y = int(y * image.height)
return x, y
@abstractmethod
def patch_image(self, patch: "Patch", image: Image.Image) -> Image.Image:
"""
Patch an image with the actual layer. Return the new image.
"""
class ColorLayer(AbstractLayer):
""" """
return a tuple of a bbox from x1, x2, y1, y2 Represent a layer that fill a rectangle with a certain color on the image
if float, calculate the position like a percentage on the image
if int, use directly the position
""" """
if isinstance(x1 := self.x1, float): x1 = int(x1 * image.width) type = "color"
if isinstance(y1 := self.y1, float): y1 = int(y1 * image.height)
if isinstance(x2 := self.x2, float): x2 = int(x2 * image.width)
if isinstance(y2 := self.y2, float): y2 = int(y2 * image.height)
return x1, y1, x2, y2 def __init__(self, color: tuple[int] = (0,), x1: int | float = 0, y1: int | float = 0,
x2: int | float = 1,
y2: int | float = 1):
self.x1: int = x1
self.y1: int = y1
self.x2: int = x2
self.y2: int = y2
self.color: tuple[int] = tuple(color)
def get_bbox_size(self, image: Image.Image) -> tuple: def patch_image(self, patch: "Patch", image: Image.Image):
draw = ImageDraw.Draw(image)
draw.rectangle(self.get_bbox(image), self.color)
return image
class ImageLayer(AbstractLayer):
""" """
return the size that a layer use on the image Represent a layer that paste an image on the image
""" """
x1, y1, x2, y2 = self.get_bbox(image) type = "image"
return x2 - x1, y2 - y1
def get_font_size(self, image: Image.Image) -> int: def __init__(self, image_path: str, x1: int | float = 0, y1: int | float = 0, x2: int | float = 1,
y2: int | float = 1):
self.x1: int = x1
self.y1: int = y1
self.x2: int = x2
self.y2: int = y2
self.image_path: str = image_path
def patch_image(self, patch: "Patch", image: Image.Image) -> Image.Image:
# check if the path is outside of the allowed directory
layer_image_path = patch.path / self.image_path
if not layer_image_path.is_relative_to(patch.path):
raise PathOutsidePatch(layer_image_path, patch.path)
layer_image = Image.open(layer_image_path).resize(self.get_bbox_size(image)).convert("RGBA")
image.paste(
layer_image,
box=self.get_bbox(image),
mask=layer_image
)
return image
class TextLayer(AbstractLayer):
""" """
return the font_size of a layer Represent a layer that write a text on the image
""" """
return int(self.font_size * image.height) if isinstance(self.font_size, float) else self.font_size type = "text"
def get_layer_position(self, image: Image.Image) -> tuple: def __init__(self, text: str, font_path: str | None = None, font_size: int = 10,
""" color: tuple[int] = (255,),
return a tuple of the x and y position x: int | float = 0, y: int | float = 0):
if x / y is a float, calculate the position like a percentage on the image self.x: int = x
if x / y is an int, use directly the position self.y: int = y
""" self.font_path: str | None = font_path
if isinstance(x := self.x, float): x = int(x * image.width) self.font_size: int = font_size
if isinstance(y := self.y, float): y = int(y * image.height) self.color: tuple[int] = tuple(color)
self.text: str = text
return x, y def patch_image(self, patch: "Patch", image: Image.Image) -> Image.Image:
draw = ImageDraw.Draw(image)
@abstractmethod if self.font_path is not None:
def patch_image(self, patch: "Patch", image: Image.Image) -> Image.Image: font_image_path = patch.path / self.font_path
""" if not font_image_path.is_relative_to(patch.path):
Patch an image with the actual layer. Return the new image. raise PathOutsidePatch(font_image_path, patch.path)
""" else:
font_image_path = None
class ColorLayer(Layer): font = ImageFont.truetype(
""" font=str(font_image_path.resolve())
Represent a layer that fill a rectangle with a certain color on the image if isinstance(font_image_path, Path) else
""" font_image_path,
type = "color" size=self.get_font_size(image)
)
draw.text(self.get_layer_position(image), text=self.text, fill=self.color, font=font)
def __init__(self, color: tuple[int] = (0,), x1: int | float = 0, y1: int | float = 0, x2: int | float = 1, return image
y2: int | float = 1):
self.x1: int = x1
self.y1: int = y1
self.x2: int = x2
self.y2: int = y2
self.color: tuple[int] = tuple(color)
def patch_image(self, patch: "Patch", image: Image.Image): class ImageEncoder(Operation):
draw = ImageDraw.Draw(image)
draw.rectangle(self.get_bbox(image), self.color)
return image
class ImageLayer(Layer):
"""
Represent a layer that paste an image on the image
"""
type = "image"
def __init__(self, image_path: str, x1: int | float = 0, y1: int | float = 0, x2: int | float = 1,
y2: int | float = 1):
self.x1: int = x1
self.y1: int = y1
self.x2: int = x2
self.y2: int = y2
self.image_path: str = image_path
def patch_image(self, patch: "Patch", image: Image.Image) -> Image.Image:
# check if the path is outside of the allowed directory
layer_image_path = patch.path / self.image_path
if not layer_image_path.is_relative_to(patch.path): raise PathOutsidePatch(layer_image_path, patch.path)
layer_image = Image.open(layer_image_path).resize(self.get_bbox_size(image)).convert("RGBA")
image.paste(
layer_image,
box=self.get_bbox(image),
mask=layer_image
)
return image
class TextLayer(Layer):
"""
Represent a layer that write a text on the image
"""
type = "text"
def __init__(self, text: str, font_path: str | None = None, font_size: int = 10, color: tuple[int] = (255,),
x: int | float = 0, y: int | float = 0):
self.x: int = x
self.y: int = y
self.font_path: str | None = font_path
self.font_size: int = font_size
self.color: tuple[int] = tuple(color)
self.text: str = text
def patch_image(self, patch: "Patch", image: Image.Image) -> Image.Image:
draw = ImageDraw.Draw(image)
if self.font_path is not None:
font_image_path = patch.path / self.font_path
if not font_image_path.is_relative_to(patch.path):
raise PathOutsidePatch(font_image_path, patch.path)
else:
font_image_path = None
font = ImageFont.truetype(font=font_image_path, size=self.get_font_size(image))
draw.text(self.get_layer_position(image), text=self.text, fill=self.color, font=font)
return image
class TplConverter(Operation):
""" """
convert an image to a tpl file encode an image to a game image file
""" """
type = "tpl-encode" type = "img-encode"
def __init__(self, *args, **kwargs): def __init__(self, encoding: str = "CMPR"):
print(args, kwargs) """
:param encoding: compression of the image
"""
self.encoding: str = encoding
def patch(self, patch: "Patch", file_name: str, file_content: IO) -> (str, IO): def patch(self, patch: "Patch", file_name: str, file_content: IO) -> (str, IO):
return file_name, file_content """
Patch a file to encode it in a game image file
:param patch: the patch that is applied
:param file_name: the file_name of the file
:param file_content: the content of the file
:return: the new name and new content of the file
"""
# remove the last extension of the filename
patched_file_name = file_name.rsplit(".", 1)[0]
patch_content = BytesIO()
# write the image to a temporary directory
tmp_file = Path(f"./.tmp/{file_name}")
tmp_file.parent.mkdir(parents=True, exist_ok=True)
file_content.seek(0)
tmp_file.write_bytes(file_content.read())
# write the encoded image into the file
patch_content.write(
IMGPath(tmp_file).get_encoded_data(self.encoding)
)
# delete the temporary directory when finished
tmp_file.unlink()
patch_content.seek(0)
return patched_file_name, patch_content
class BmgEditor(Operation): class BmgEditor(Operation):
""" """
edit a bmg edit a bmg
""" """
type = "bmg-replace" type = "bmg-edit"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
print(args, kwargs) print(args, kwargs)

View file

@ -20,26 +20,11 @@ class InvalidImageLayerType(Exception):
def __init__(self, layer_type: str): def __init__(self, layer_type: str):
super().__init__(f"Error : layer type \"{layer_type}\" is not implemented") super().__init__(f"Error : layer type \"{layer_type}\" is not implemented")
# TODO : extract SZS
# TODO : implement TPL
# TODO : implement BMG # TODO : implement BMG
# TODO : recreate SZS
configuration_example = { configuration_example = {
"operation": { # other operation for the file "operation": { # other operation for the file
"tpl-encode": {"encoding": "TPL.RGB565"}, # encode an image to a tpl with the given format
"bmg-replace": { "bmg-replace": {
"mode": "regex", # regex or id "mode": "regex", # regex or id
"template": { "template": {

View file

@ -0,0 +1,33 @@
from source.wt import *
from source.wt import _run
tools_path = tools_szs_dir / ("wimgt.exe" if system == "win64" else "wimgt")
@better_wt_error(tools_path)
class IMGPath:
"""
Represent a path to an image
"""
__slots__ = ("path", )
def __init__(self, path: Path | str):
self.path: Path = Path(path)
@better_wt_error(tools_path)
def _run(self, *args) -> bytes:
"""
Return a command with wszst and return the output
:param args: command arguments
:return: the output of the command
"""
return _run(tools_path, *args)
def get_encoded_data(self, transform: str = "CMPR") -> bytes:
"""
Convert the image return the encoded image data
:transform: the type of the image encoding
:return: the data of the encoded image
"""
# using "-" for destination allow for output in the stdout
return self._run("ENCODE", self.path, "--transform", transform, "--DEST", "-")