Compare commits

...

6 commits

6 changed files with 95 additions and 26 deletions

View file

@ -13,9 +13,11 @@ namespace Kanimaji
std::string Animate(const std::string& source, std::string Animate(const std::string& source,
const AnimationSettings& settings = AnimationSettings::Default()); const AnimationSettings& settings = AnimationSettings::Default());
void RemoveStrokeNumbers(const std::string& source, const std::string& destination); void RemoveStrokeNumbers(const std::string& source, const std::string& destination,
const RemovalSetttings& settings = RemovalSetttings::Default());
std::string RemoveStrokeNumbers(const std::string& source); std::string RemoveStrokeNumbers(const std::string& source,
const RemovalSetttings& settings = RemovalSetttings::Default());
} }
#endif // KANIMAJI_KANIMAJI_HPP #endif // KANIMAJI_KANIMAJI_HPP

View file

@ -49,6 +49,13 @@ namespace Kanimaji
static AnimationSettings Default(); static AnimationSettings Default();
}; };
struct RemovalSetttings
{
StrokeStyle Style;
static RemovalSetttings Default();
};
} }
#endif // KANIMAJI_CONFIG_HPP #endif // KANIMAJI_CONFIG_HPP

View file

@ -12,42 +12,55 @@ namespace Kanimaji
{ {
namespace namespace
{ {
using namespace std::string_view_literals; constexpr std::string_view StaticStrokeStyleFormat(
constexpr auto StrokeProgressionFormat = "fill:none;stroke:{};stroke-width:{};stroke-linecap:round;stroke-linejoin:round;"
);
constexpr std::string_view StrokeProgressionFormat(
" " " "
"@keyframes stroke-{} {{ " "@keyframes stroke-{} {{ "
"0.000% {{ stroke-dashoffset: {:.3f}; }} " "0.000% {{ stroke-dashoffset: {:.3f}; }} "
"{:.3f}% {{ stroke-dashoffset: {:.3f}; }} " "{:.3f}% {{ stroke-dashoffset: {:.3f}; }} "
"{:.3f}% {{ stroke-dashoffset: 0; }} " "{:.3f}% {{ stroke-dashoffset: 0; }} "
"100.000% {{ stroke-dashoffset: 0; }} }}\n"sv; "100.000% {{ stroke-dashoffset: 0; }} }}\n"
constexpr auto AnimationVisibilityFormat = );
constexpr std::string_view AnimationVisibilityFormat(
" " " "
"@keyframes display-{} {{ " "@keyframes display-{} {{ "
"{:.3f}% {{ visibility: hidden; }} " "{:.3f}% {{ visibility: hidden; }} "
"{:.3f}% {{ stroke: {}; }} }}\n"sv; "{:.3f}% {{ stroke: {}; }} }}\n"
constexpr auto AnimationProgressionFormat = );
constexpr std::string_view AnimationProgressionFormat(
" " " "
"#{} {{ " "#{} {{ "
"stroke-dasharray: {:.3f} {:.3f}; " "stroke-dasharray: {:.3f} {:.3f}; "
"stroke-dashoffset: 0; " "stroke-dashoffset: 0; "
"animation: stroke-{} {:.3f}s {} infinite, " "animation: stroke-{} {:.3f}s {} infinite, "
"display-{} {:.3f}s step-start infinite; }}\n"sv; "display-{} {:.3f}s step-start infinite; }}\n"
constexpr auto BrushVisibilityFormat = );
constexpr std::string_view BrushVisibilityFormat(
" " " "
"@keyframes display-brush-{} {{ " "@keyframes display-brush-{} {{ "
"{:.3f}% {{ visibility: hidden; }} " "{:.3f}% {{ visibility: hidden; }} "
"{:.3f}% {{ visibility: visible; }} " "{:.3f}% {{ visibility: visible; }} "
"100.000% {{ visibility: hidden; }} }}\n"sv; "100.000% {{ visibility: hidden; }} }}\n"
constexpr auto BrushProgressionFormat = );
constexpr std::string_view BrushProgressionFormat(
" " " "
"#{}, #{} {{ " "#{}, #{} {{ "
"stroke-dasharray: 0 {:.3f}; " "stroke-dasharray: 0 {:.3f}; "
"animation: stroke-{} {:.3f}s {} infinite, " "animation: stroke-{} {:.3f}s {} infinite, "
"display-brush-{} {:.3f}s step-start infinite; }}\n"sv; "display-brush-{} {:.3f}s step-start infinite; }}\n"
);
constexpr auto StylesHeader = constexpr std::string_view StylesHeader(
"\n " "\n "
"/* Styles generated automatically by Kanimaji, please avoid editing manually. */\n"sv; "/* Styles generated automatically by Kanimaji, please avoid editing manually. */\n"
);
double AsSeconds(auto duration) { double AsSeconds(auto duration) {
return std::max(0.0, duration.count()); return std::max(0.0, duration.count());
@ -65,8 +78,7 @@ namespace Kanimaji
pugi::xml_node newGroup = svg.append_child("g"); pugi::xml_node newGroup = svg.append_child("g");
newGroup.append_attribute("id") = name; newGroup.append_attribute("id") = name;
newGroup.append_attribute("style") = std::format( newGroup.append_attribute("style") = std::format(
"fill:none;stroke:{};stroke-width:{};stroke-linecap:round;stroke-linejoin:round;", StaticStrokeStyleFormat, config.Colour.ToHex(), config.Width
config.Colour.ToHex(), config.Width
); );
return newGroup; return newGroup;
} }
@ -270,7 +282,8 @@ namespace Kanimaji
return str.str(); return str.str();
} }
void RemoveStrokeNumbers(const std::string& source, const std::string& destination) void RemoveStrokeNumbers(const std::string& source, const std::string& destination,
const RemovalSetttings& settings)
{ {
pugi::xml_document doc; pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(source.c_str(), pugi::parse_full); pugi::xml_parse_result result = doc.load_file(source.c_str(), pugi::parse_full);
@ -284,6 +297,13 @@ namespace Kanimaji
throw Error("Unexpected document format: Expected to find a SVG element"); throw Error("Unexpected document format: Expected to find a SVG element");
} }
pugi::xml_node pathsGroup = svg.find_child([](pugi::xml_node& node) {
return std::string_view(node.attribute("id").as_string()).contains("StrokePaths");
});
pathsGroup.attribute("style") = std::format(
StaticStrokeStyleFormat, settings.Style.Colour.ToHex(), settings.Style.Width
);
RemoveStrokeNumbers(svg); RemoveStrokeNumbers(svg);
if (!doc.save_file(destination.c_str())) { if (!doc.save_file(destination.c_str())) {
@ -291,7 +311,7 @@ namespace Kanimaji
} }
} }
std::string RemoveStrokeNumbers(const std::string& source) std::string RemoveStrokeNumbers(const std::string& source, const RemovalSetttings& settings)
{ {
pugi::xml_document doc; pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_string(source.c_str(), pugi::parse_full); pugi::xml_parse_result result = doc.load_string(source.c_str(), pugi::parse_full);
@ -305,6 +325,13 @@ namespace Kanimaji
throw Error("Unexpected document format: Expected to find a SVG element"); throw Error("Unexpected document format: Expected to find a SVG element");
} }
pugi::xml_node pathsGroup = svg.find_child([](pugi::xml_node& node) {
return std::string_view(node.attribute("id").as_string()).contains("StrokePaths");
});
pathsGroup.attribute("style") = std::format(
StaticStrokeStyleFormat, settings.Style.Colour.ToHex(), settings.Style.Width
);
RemoveStrokeNumbers(svg); RemoveStrokeNumbers(svg);
std::stringstream str; std::stringstream str;

View file

@ -48,4 +48,14 @@ namespace Kanimaji
.DelayBetweenStrokes = 50ms, .DelayBetweenStrokes = 50ms,
}; };
} }
RemovalSetttings RemovalSetttings::Default()
{
return RemovalSetttings {
.Style = StrokeStyle {
.Width = 3.0,
.Colour = RGB::FromHex("#000000"),
},
};
}
} }

View file

@ -64,11 +64,9 @@ namespace Tablegen
constexpr std::string ImageStyle(std::string_view indent, constexpr std::string ImageStyle(std::string_view indent,
std::size_t index, std::size_t index,
std::string_view imageName, std::string_view imagePath,
std::string_view imageFormat,
std::string_view extraSpecifier = "") std::string_view extraSpecifier = "")
{ {
std::string imagePath = std::vformat(imageFormat, std::make_format_args(imageName));
return std::format(imageStyleFormat, indent, index, extraSpecifier, imagePath); return std::format(imageStyleFormat, indent, index, extraSpecifier, imagePath);
} }
@ -138,6 +136,9 @@ namespace Tablegen
pugi::xml_node comment = table.append_child(pugi::node_comment); pugi::xml_node comment = table.append_child(pugi::node_comment);
comment.set_value(" Autogenerated by Tablegen, please avoid editing manually. "); comment.set_value(" Autogenerated by Tablegen, please avoid editing manually. ");
pugi::xml_node preload = table.append_child("div");
preload.append_attribute("hidden") = "hidden";
pugi::xml_node script = table.append_child("script"); pugi::xml_node script = table.append_child("script");
pugi::xml_node styles = table.append_child("style"); pugi::xml_node styles = table.append_child("style");
@ -154,9 +155,26 @@ namespace Tablegen
pugi::xml_node tableBody = table.append_child("tbody"); pugi::xml_node tableBody = table.append_child("tbody");
for (pugi::xml_node row; const auto& [i, character] : vw::enumerate(characters)) { for (pugi::xml_node row; const auto& [i, character] : vw::enumerate(characters)) {
std::string imagePath = std::vformat(
settings.ImageFormat, std::make_format_args(character.ImagePath)
);
std::string animationPath = std::vformat(
settings.AnimationFormat, std::make_format_args(character.AnimationPath)
);
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// HTML // HTML
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
pugi::xml_node preloadImage = preload.append_child("link");
preloadImage.append_attribute("rel") = "preload";
preloadImage.append_attribute("href") = imagePath;
preloadImage.append_attribute("as") = "image";
pugi::xml_node preloadAnimation = preload.append_child("link");
preloadAnimation.append_attribute("rel") = "preload";
preloadAnimation.append_attribute("href") = animationPath;
preloadAnimation.append_attribute("as") = "image";
if (i % settings.CharactersPerRow == 0) { if (i % settings.CharactersPerRow == 0) {
row = tableBody.append_child("tr"); row = tableBody.append_child("tr");
row.append_attribute("class") = "kanji-table-row"; row.append_attribute("class") = "kanji-table-row";
@ -188,9 +206,8 @@ namespace Tablegen
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// CSS // CSS
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
staticImg.append(ImageStyle(indent, i, character.ImagePath, settings.ImageFormat)); staticImg.append(ImageStyle(indent, i, imagePath));
animatedImg.append(ImageStyle(indent, i, character.AnimationPath, animatedImg.append(ImageStyle(indent, i, animationPath, ":checked"));
settings.AnimationFormat, ":checked"));
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// JavaScript // JavaScript

View file

@ -21,6 +21,12 @@ void AnimateFile(const Path& source, const Path& destination,
std::string Animate(const std::string& source, std::string Animate(const std::string& source,
const AnimationSettings& settings = AnimationSettings::Default()); const AnimationSettings& settings = AnimationSettings::Default());
void RemoveStrokeNumbers(const std::string& source, const std::string& destination,
const RemovalSetttings& settings = RemovalSetttings::Default());
std::string RemoveStrokeNumbers(const std::string& source,
const RemovalSetttings& settings = RemovalSetttings::Default());
``` ```
The former function takes in two paths, where the first one specifies the file to be read, and The former function takes in two paths, where the first one specifies the file to be read, and
@ -113,7 +119,7 @@ Some caveats:
The default settings generate a table with no characters (and horrible styling), you will need to The default settings generate a table with no characters (and horrible styling), you will need to
specify custom settings like this for actual use: specify custom settings like this for actual use:
```cpp ```cpp
auto doc = GeneratePage({ auto doc = GeneratePage(std::vector<CharacterInfo>(), {
.FullDocument = Flag::Enable, .FullDocument = Flag::Enable,
.OverrideIndentLevel = Flag::Disable, .OverrideIndentLevel = Flag::Disable,
.IndentLevel = 0, .IndentLevel = 0,